使用了顶点缓冲技术,绘制效率有了很大的提升。但是还有一点不尽如人意,就是每次使用顶点的位置坐标、法向量、纹理坐标等不同方面的数据都需要分别指定,重复了一些无谓的工作。WebGL2提供了一个专门用来解决这个问题的对象——顶点数组对象(VAO)。本节介绍顶点数组对象。顶点数组对象,在WebGL1中,是一个扩展对象,扩展对象的名称为OES_vertex_array_object;可以直接在WebGL2中使用;如果你在WebGL1中使用过OES_vertex_array_object,那么你只需要了解WebGL2和WebGL1中的调用方法的区别,下面会详细介绍顶点数组对象。VertexArrayObjectVertexArrayObject(VAO)是封装了所有与顶点处理器相关的数据的对象,它记录了对顶点缓冲区和索引缓冲区的引用,以及顶点各种属性的布局,而不是实际数据。顶点数组对象的优点这样做的优点是:一旦为对象指定了VAO,则只需绑定VAO对象即可导入该对象的所有引用和状态。以后绘制对象时,你不需要手动导入对象的引用和状态,VAO帮你记住了。VAO可以简化缓冲区绑定过程,从而可以减少代码调用次数,提高WebGL状态切换的效率。示例:使用顶点数组对象绘制两个三角形下面的代码说明了顶点数组对象的用法。本例代码绘制了两个顶点颜色不同的三角形,最终显示效果如下:vartriangleArray=gl.createVertexArray();gl.bindVertexArray(triangleArray);varpositions=newFloat32Array([-0.5,-0.5,0.0,0.0,-0.5,0.0,0.0,0.0,0.0]);varpositionBuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);gl.bufferData(gl.ARRAY_BUFFER,位置,gl.STATIC_DRAW);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(0);varcolors=newFloat32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]);varcolorBuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);gl.bufferData(gl.ARRAY_BUFFER,颜色,gl.STATIC_DRAW);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(1);var三角形数组2=gl.createVertexArray();gl.bindVertexArray(triangleArray2);varpositions2=newFloat32Array([0.0,-0.0,0.0,0.5,0.0,0.0,0.0,0.5,0.0]);varpositionBuffer2=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer2);gl.bufferData(gl.ARRAY_BUFFER,positions2,gl.STATIC_DRAW);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(0);varcolors2=newFloat32Array([1.0,1.0,0.0,0.0,1.0,1.0,0.0,1.0,1.0]);varcolorBuffer2=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer2);gl.bufferData(gl.ARRAY_BUFFER,colors2,gl.STATIC_DRAW);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(1);/////////////////绘制///////////////gl.clear(gl.COLOR_BUFFER_BIT);gl.bindVertexArray(triangleArray);gl.drawArrays(gl.TRIANGLES,0,3);gl.bindVertexArray(triangleArray2);gl.drawArrays(gl.TRIANGLES,0,3);定义三角形相关的数据和缓冲区首先,定义三角形的顶点数据和缓冲区,和WebGL1的代码很相似。下面是定义三角形相关数据的代码vartriangleArray=gl.createVertexArray();gl.bindVertexArray(triangleArray);varpositions=newFloat32Array([-0.5,-0.5,0.0,0.0,-0.5,0.0,0.0,0.0,0.0]);varpositionBuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);gl.bufferData(gl.ARRAY_BUFFER,位置,gl.STATIC_DRAW);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(0);varcolors=newFloat32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]);varcolorBuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);gl.bufferData(gl.ARRAY_BUFFER,颜色,gl.STATIC_DRAW);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(1);可以看到除了前两行VAO创建和绑定VAO代码外,其他代码和WebGL1的代码一样:定义坐标数组,创建顶点坐标缓冲区,绑定缓冲区并填充缓冲区数据,赋值缓冲区到属性变量并启用属性变量。代码中定义了两种顶点信息:顶点坐标和顶点颜色创建另一个三角形相关数据的代码与第一种类似,VAO对象在创建顶点数据中的作用不再赘述。现在回到前面两行代码:vartriangleArray=gl.createVertexArray();gl.bindVertexArray(triangleArray);第一行代码创建了一个VAO对象,第二行代码绑定了VAO对象。这两行代码的作用是:顶点缓冲对象的操作和状态都会记录在这个VAO对象中。绘制时,只需要调用gl.bindVertexArray方法绑定对象,相关状态就会自动使用。VAO对象在绘图时的作用。我们看绘图代码gl.clear(gl.COLOR_BUFFER_BIT);//清除颜色缓冲区//绘制第一个三角形gl.bindVertexArray(triangleArray);gl.drawArrays(gl.TRIANGLES,0,3);//绘制第二个三角形gl.bindVertexArray(triangleArray2);gl.drawArrays(gl.TRIANGLES,0,3);第一行代码,清除颜色缓冲区,同WebGL1;然后绘制第一个三角形时,先调用gl.bindVertexArray(triangleArray)恢复第一个三角形相关的缓冲状态,然后调用gl.drawArrays(gl.TRIANGLES,0,3)绘制第二个三角形和首先同样;回想一下,不使用顶点数组对象绘制第一个三角形的代码如下所示:gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(0);gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(1);.drawArrays(gl.TRIANGLES,0,3);绘制第二个三角形是相似的。可以看出,在使用了VAO对象之后,gl.bindVertexArray这行代码相当于下面的代码:gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(0);gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0);gl。enableVertexAttribArray(1);即绑定缓冲区对象、分配属性和启用属性变量等在绘制时不能再调用。曾经可以看出使用VAO对象的好处:减少代码量,提高开发效率,提高绘图效率(因为减少了WebGL相关函数的调用,在WebGL内部优化了VAO)。如何在WebGL1中使用VAO。在WebGL1.0中,VAO是通过扩展提供的。首先需要获取对应的扩展对象:varext=gl.getExtension("OES_vertex_array_object");如果返回的ext位为null,表示浏览器不支持该扩展。使用上面的ext对象,您可以创建一个VAO:varvao=ext.createVertexArrayOES();有了VAO对象后,就可以进行绑定操作了://bindext.bindVertexArrayOES(vao);//unbindext.bindVertexArrayOES(null);
