WebGL 2.0實現Vertex Array Objects(VAO,頂點數組對象)

       在WebGL 2.0中,終於把VAO轉正了。在WebGL 1.0中,可以通過拓展實現。Babylon.js引擎默認情況下,每次渲染都使用VAO完成。簡單介紹下VAO,下面截取自《OpenGLES 3.0 Programming Guide》。

In OpenGL ES 3.0, a new feature was introduced to make using vertex arrays even more efficient: vertex array objects (VAOs). As we have seen, setting up drawing using vertex buffer objects can require many calls to glBindBuffer, glVertexAttribPointer, and glEnableVertexAttribArray. To make it faster to switch between vertex array configurations, OpenGL ES 3.0 introduced vertex array objects. VAOs provide a single object that contains all of the state required to switch between vertex array/vertex buffer object configurations.

     那其實VAO主要是將一個繪製物體的各種頂點緩衝(VBO)包裝一個整體。頂點緩衝可以有頂點座標,紋理座標等。優點就在於能提高開發效率,它將所有頂點繪製過程中的這些頂點的設置和綁定過程集中存儲在一起,當我們需要時,只需要使用相應的VAO即可。VAO的這種方式有點像一箇中介,把所有繁瑣的綁定和頂點設置工作都集中起來處理,我們需要繪製時,直接找這個中介就好了。那接下來。我們來看看WebGL 2.0中關於VAO的API信息。

Vertex Array Objects [3.7.17]

VAOs encapsulate all state related to the definition of data used by the vertex processor.

void bindVertexArray( WebGLVertexArrayObject? vertexArray);

WebGLVertexArrayObject? createVertexArray();

void deleteVertexArray( WebGLVertexArrayObject? vertexArray);

[WebGLHandlesContextLoss] boolean isVertexArray( WebGLVertexArrayObject? vertexArray);

      有了API的瞭解,我們來看看大體的繪製流程吧,其實也很簡單拉。

       1.創建不同的頂點緩衝(VBO),像頂點座標,紋理座標等等

       2. 利用createVertex()創建VAO。

       3.調用bindVertexArray綁定VAO,之後就是日常操作,調用enableVertexAttribArray(),bindBuffer(),vertexAttribPointer()等影響綁定的VAO,也就是組裝成一個VAO。

        4.在繪製物體的時候 ,我們只需指定VAO即可。

     那接下我們看案例吧,這個是運行效果圖。

首先,我們看看創建VBO的代碼,對應上面的步驟1,這裏也僅僅是給個代碼Demo,不全。

//創建頂點VBO
this.vertexBuffer=gl.createBuffer();				
gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 	
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(this.vertexData),gl.STATIC_DRAW);

 下面是代碼,將多個VBO(頂點座標和紋理座標)包裝成1個VAO。對應步驟2和3。

    this.program=programIn;		         //着色器程序
    this.VAOArray=gl.createVertexArray();        //創建VAO數組對象
    gl.bindVertexArray(this.VAOArray);           //綁定VAO

    //啓用頂點座標數據數組
    gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aPosition"));
    //綁定頂點座標數據緩衝
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    //給管線指定頂點座標數據
    gl.vertexAttribPointer(gl.getAttribLocation(this.program, "aPosition"), 3, gl.FLOAT, false, 0, 0);

    //啓用頂點紋理座標數據數組
    gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aTexCoor"));
    //綁定頂點紋理座標數據緩衝
    gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
    //給管線指定頂點紋理座標數據
    gl.vertexAttribPointer(gl.getAttribLocation(this.program, "aTexCoor"), 2, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    gl.bindVertexArray(null)

現在 我們來看繪製的方法。對應步驟4,繪製物體的時候指定VAO

this.drawSelf=function(ms,texture)//繪製物體的方法
{
	//指定使用某套着色器程序	
	gl.useProgram(this.program);	
		
	//獲取總變換矩陣引用id
	var uMVPMatrixHandle=gl.getUniformLocation(this.program, "uMVPMatrix");
	//將總變換矩陣送入渲染管線		
	gl.uniformMatrix4fv(uMVPMatrixHandle,false,new Float32Array(ms.getFinalMatrix()));

        //設置VAO
        gl.bindVertexArray(this.VAOArray);

        gl.activeTexture(gl.TEXTURE0);//設置使用的紋理編號-0
        gl.bindTexture(gl.TEXTURE_2D, texture);//綁定紋理
        gl.uniform1i(gl.getUniformLocation(this.program, "sTexture"), 0);//紋理送入管線
        
        //用頂點法繪製物體
	gl.drawArrays(gl.TRIANGLES, 0, this.vcount);
		
        gl.bindVertexArray(null)
} 

最後要說的是gl.bindVertexArray(null)主要是解綁VAO,不解綁的話會影響後面的很多操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章