使用了顶点缓冲技术后,绘制效率有了较大的提升。但是还有一点不尽如人意,那就是顶点的位置坐标、法向量、纹理坐标等不同方面的数据每次使用时需要单独指定,重复了一些不必要的工作。WebGL2提供了一种专门用于解决此问题的对象——顶点数组对象(VAO)。本节将介绍顶点数组对象。

顶点数组对象,在WebGL1中,是一个扩展对象,该扩展对象的名称是OES_vertex_array_object;而在WebGL2中可以直接使用;如果你在WebGL1中已经使用过OES_vertex_array_object,那么你只需要了解在WebGL2和WebGL1的调用方式的差异即可

下面会对顶点数组对象做详细的介绍。

顶点数组对象

顶点数组对象( VAO )是这样一种对象: 它封装了与顶点处理器有关的所有数据,它记录了顶点缓存区和索引缓冲区的引用,以及顶点的各种属性的布局而不是实际的数据。

顶点数组对象的优点

这样做的优点是: 一旦为一个 对象指定了一个VAO之后,可以ton通过对该VAO对象进行简单的绑定操作来导入对象的所有引用和状态。在之后绘制对象时候,不需要在手动来导入对象的引用和状态,VAO替你记住了它。
通过VAO可以简化缓冲区的绑定过程,即可以减少代码的调用次数,也提升了WebGL状态切换的效率。

案例:用顶点数组对象绘制两个三角形

下面通过代码来说明顶点数组对象的使用,本案例代码绘制两个顶点色的三角形,最终显示的效果如下:

var triangleArray = gl.createVertexArray();
gl.bindVertexArray(triangleArray); var positions = new Float32Array([
-0.5, -0.5, 0.0,
0.0, -0.5, 0.0,
0.0, 0.0, 0.0
]);
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
var colors = new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
]);
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(1); var triangleArray2 = gl.createVertexArray();
gl.bindVertexArray(triangleArray2); var positions2 = new Float32Array([
0.0, -0.0, 0.0,
0.5, 0.0, 0.0,
0.0, 0.5, 0.0
]);
var positionBuffer2 = 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);
var colors2 = new Float32Array([
1.0, 1.0, 0.0,
0.0, 1.0, 1.0,
0.0, 1.0, 1.0
]);
var colorBuffer2 = 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);
////////////////
// DRAW
////////////////
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的代码很类似,下面是一个三角相关数据定义的代码

var triangleArray = gl.createVertexArray();
gl.bindVertexArray(triangleArray); var positions = new Float32Array([
-0.5, -0.5, 0.0,
0.0, -0.5, 0.0,
0.0, 0.0, 0.0
]);
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
var colors = new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
]);
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(1);

可以看出除了前两行 创建VAO和绑定VAO代码外,其他的代码都是WebGL1一样的代码:

    • 定义坐标数组
    • 创建顶点坐标缓冲区
    • 绑定缓冲区并填充缓冲区数据
    • 把缓冲区分配给attribute变量
    • 启用attribute变量

    代码中定义了两种顶点信息:顶点坐标和顶点颜色

    创建另外一个三角形的相关数据的代码和第一个类似,不重复说明。

    VAO对象在创建顶点数据的作用

    现在回到前面两行代码:

    var triangleArray = 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); gl.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);

    也就是绑定缓冲区对象,分配attribute和启用attribute变量等等操作都可以在绘制的时候可以不再调用了。 有次可以看出,使用VAO对象的好处:

    • 减少代码量,提高开发效率
    • 提高绘制效率(因为减少了WebGL相关函数的调用,并且WebGL内部对VAO进行了优化)

    WebGL1中如何使用VAO

    在WebGL1.0中VAO是通过扩展方式提供的,首先需要获取对应的扩展对象:

    var ext = gl.getExtension("OES_vertex_array_object");

    如果返回的ext位null说明浏览器不支持该扩展。
    有了上面的ext对象,便可以创建VAO了:

    var vao = ext.createVertexArrayOES();

    有了VAO对象之后,就可以进行绑定操作:

    // bind
    ext.bindVertexArrayOES(vao);
    // unbind
    ext.bindVertexArrayOES(null);

    WebGL2系列之顶点数组对象的更多相关文章

    1. Opengl_入门学习分享和记录_03_渲染管线(三)借助顶点数组对象VAO提高绑定属性效率

      目前我们已经知道了,如果想要顶点着色器解释理解我们的输入数据,就必须要按照以下繁琐的步骤:第一步:将输入的数据复制一份到缓冲区,供OpenGL使用.而这块新出现的区域由VBO管理和表示.(若有多个输入 ...

    2. 3D Computer Grapihcs Using OpenGL - 19 Vertex Array Object(顶点数组对象)

      大部分OpenGL教程都会在一开始就讲解VAO,但是该教程的作者认为这是很不合理的,因为要理解它的作用需要建立在我们此前学过的知识基础上.因此直到教程已经进行了一大半,作者才引入VAO这个概念.在我看 ...

    3. WebGL2系列之实例数组(Instanced Arrays)

      实例化数组 实例化是一种只调用一次渲染函数却能绘制出很多物体的技术,它节省渲染一个物体时从CPU到GPU的通信时间.实例数组是这样的一个对象,使用它,可以把原来的的uniform变量转换成attrib ...

    4. OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别

      OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及VAO区别 1.glVertex 最原始的设置顶点方法,在glBegin和glEnd之间 ...

    5. MVVM架构~knockoutjs系列之为Ajax传递Ko数组对象

      返回目录 一些要说的 这是一个很有意思的题目,在KO里,有对象和数组对象两种,但这两种对象对外表现都是一个function,如果希望得到他的值,需要进行函数式调用,如ko_a(),它的结果为一个具体值 ...

    6. 顶点缓存对象(VBO)

      创建VBO 绘制VBO 更新VBO 实例 GL_ARB_vertex_buffer_object扩展致力于提供顶点数组与显示列表的优势来提升OpenGL效率,同时避免它们实现上的不足.顶点缓存对象(V ...

    7. OpenGL顶点数组

      概述 作为在立即模式(glBegin()与glEnd()之间)下指定单个顶点数据的替代,你可以保存顶点数据在一组列表中,包括顶点位置.法线.纹理坐标与颜色信息.并且你可以通过索引数组解引用数组元素绘制 ...

    8. OpenGL顶点缓冲区对象(VBO)

      转载 http://blog.csdn.net/dreamcs/article/details/7702701 创建VBO        GL_ARB_vertex_buffer_object 扩展可 ...

    9. openGL 提升渲染性能 之 顶点数组 VBO IBO VAO

      使用openGL图形库绘制,都需要通过openGL接口向图像显卡提交顶点数据,显卡根据提交的数据绘制出相应的图形. openGL绘制方式有:直接模式,显示列表,顶点数组,顶点索引. 直接模式:最简单, ...

    随机推荐

    1. c# winform中TabControl中给每个选项卡添加不同的图标(图片)

      在一个TabControl控件中,有几个选项卡,现在在每个选项卡上显示不同的图标. 1:你要现在form窗体中通过工具箱加入一个imagelist,名字为imagelist1,如下图: 2:然后在里面 ...

    2. 怎样打开win7的IIS功能及internet信息服务(IIS)管理器在哪里

      1:在windows7桌面上的左下角,点击"开始",找到"控制面板",并点击进去.如下图所示: 2:进入控制面板后,首先将"查看方式"选择为 ...

    3. numpy最后一部分及pandas初识

      今日内容概要 numpy剩余的知识点 pandas模块 今日内容详细 二元函数 加 add 减 sub 乘 mul 除 div 平方 power 数学统计方法 sum 求和 cumsum 累计求和 m ...

    4. 【实测】Python 和 C++ 下字符串查找的速度对比

      完整格式链接:https://blog.imakiseki.cf/2022/03/07/techdev/python-cpp-string-find-perf-test/ 背景 最近在备战一场算法竞赛 ...

    5. VirtualBox 桥接模式

      网桥网络配置 以下内容来自:http://www.jianshu.com/p/a4dbdb40b72b 特点 1.如果主机可以上网,虚拟机可以上网 2.虚拟机之间可以ping通 3.虚拟机可以ping ...

    6. Spring Cloud Gateway 不小心换了个 Web 容器就不能用了,我 TM 人傻了

      个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...

    7. linux文件目录权限操作

      设置修改文件的属主或修改文件属组 [root@localhost ~]# ll test.txt -rw-r--r--. 1 root root 0 Oct 21 12:01 test.txt [ro ...

    8. U8g2库的使用

      一.硬件介绍: 由于笔者这里只有0.96寸的OLED屏幕,那就讲讲最常用的0.96寸OLED屏幕吧. OLED介绍: OLED,即有机发光二极管( Organic Light Emitting Dio ...

    9. 【数据库】SQL 语句大全

      数据操作 SELECT --从数据库表中检索数据行和列 INSERT --向数据库表添加新数据行 DELETE --从数据库表中删除数据行 UPDATE --更新数据库表中的数据 数据定义 CREAT ...

    10. Blazor 001 : 一个激进的Web开发框架

      本文从比较高的位置俯瞰一下 .NET Blazor 技术方向,主要是给大家介绍一下"什么是 Blazor" 文章后半部分会给出一个 Blazor 中的 Hello World 示例 ...