WebGL2系列之顶点数组对象

公祖
• 阅读 3924

使用了顶点缓冲技术后,绘制效率有了较大的提升。但是还有一点不尽如人意,那就是顶点的位置坐标、法向量、纹理坐标等不同方面的数据每次使用时需要单独指定,重复了一些不必要的工作。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);
    点赞
    收藏
    评论区
    推荐文章
    Wesley13 Wesley13
    3年前
    janusgraph
    精确查询语句含义测试语句执行时间查询顶点标签为FALV的顶点数量g.V().hasLabel('FALV').count()2400s查询顶点属性中id为19012201clockWithResult(1){g.V().has('id','19012201')}0.18540099999999998s查询顶点属性中
    Stella981 Stella981
    3年前
    Spark GraphX图算法应用【分区策略、PageRank、ConnectedComponents,TriangleCount】
    一.分区策略  !(https://img2018.cnblogs.com/ibeta/1343081/201911/1343081201911271536266281023000587.png)  GraphX采用顶点分割的方式进行分布式图分区。GraphX不会沿着边划分图形,而是沿着顶点划分图形,这可以减少通信和存储的开
    Stella981 Stella981
    3年前
    Neo4j 第一篇:在Windows环境中安装Neo4j
    <divid"cnblogs\_post\_body"class"blogpostbody"<p图形数据库(GraphDatabase)是NoSQL数据库家族中特殊的存在,用于存储丰富的关系数据,Neo4j是目前最流行的图形数据库,支持完整的事务,在属性图中,图是由顶点(Vertex),边(Edge)和属性(Property)组成的,顶点和
    Stella981 Stella981
    3年前
    GraphLab与Pregel对比
    一、GraphLab示例1:GraphLab完成对V0邻接顶点的求和计算!(http://static.oschina.net/uploads/img/201511/01234613_w53B.png)示例中,需要完成对V0邻接顶点的求和计算,串行实现中,V0对其所有的邻接点进行遍历,累加求和。而GraphLab中,将顶
    Wesley13 Wesley13
    3年前
    Unity Mesh基础系列(四)mesh变形(制作一个弹力球)
    目录1场景搭建2Mesh调节器2.1准备2.2顶点速度3Mesh调节器的输入3.1输入检测3.2施加力3.3力偏移4最基础的变形4.1将力转换为速度4.2移动顶点5保持形状5.1弹簧5.2阻尼6处理变换6.1调整缩放本章内容重点向对象投射射线
    Wesley13 Wesley13
    3年前
    C语言实现数据结构的邻接矩阵
    写在前面  图的存储结构有两种:一种是基于二维数组的邻接矩阵表示法。            另一种是基于链表的的邻接表表示法。  在邻接矩阵中,可以如下表示顶点和边连接关系:    !(https://oscimg.oschina.net/oscnet/fe38c2aff8c2a62f0d7ab71f55c1eb1cea
    Wesley13 Wesley13
    3年前
    D3D资源管理
    摘要受管贴图(Managedtextures,也就是我们通常所谓的“自动管理贴图”),在DX6中首次被引入,经过一系列的改进和增强,在DX9中自动管理的资源类型增加到贴图,顶点缓冲,顶点索引缓冲,所有这些资源使用统一的公共接口。通过使用D3D资源管理器,应用程序可以轻松的处理设备丢失、处理稍微过量的显存使用。有时开发者在使用受管资源
    Wesley13 Wesley13
    3年前
    Unity Mesh基础系列(一)生成网格(程序生成)
    目录1渲染事物2创建顶点网格3创建Mesh4生成附加顶点数据本文主要内容:1、创建一个点阵网格2、用协程分析点阵网格的位置3、用三角形定义表面4、自动生成法线5、增加纹理坐标和切线在本教程中,我们将创建一个由顶点和三角形组成
    Wesley13 Wesley13
    3年前
    .Net转Java自学之路—基础巩固篇十三(集合)
    集合:集合是用于存储对象的一个工具。  集合与数组的特点    相同点:都是一个容器    不同点:      集合:可以存储对象,只能存储对象,集合长度可变。      数组:可以存储对象,也可以存储基本数据类型,数组长度固定。  容器对象有很多种,通过内部的数据结构来区分,数据结构就是一种数据存储方式。  在不断
    Wesley13 Wesley13
    3年前
    Unity 凹多边形三角剖分
    游戏中需要实现一个小功能,显示一个玩家的能力图,这个图是一个有6个顶点任意摆放组合的多边形。而绘制多边形主要用到的知识就是Mesh构建,mesh的构建主要需要顶点列表,三角形列表,法线列表、uv列表等等等等,在这里我们只考虑顶点列表和三角形列表。那么我们需要做的就是给定一组顶点之后,如何用三角形进行划分,以便绘制。以下讨论的多边形:1.三角形顶点列表为顺
    贾蔷 贾蔷
    2个月前
    邻接表实现指南:图结构的链表存储方式
    一、简介和特点邻接表是一种常用的图存储结构,它使用链表来表示图中顶点之间的邻接关系。本文实现的邻接表类可以高效地表示稀疏图,并支持动态添加顶点和边。‌主要特点‌:空间效率:特别适合存储稀疏图动态扩展:可以灵活添加顶点和边直观表示:直接反映图的连接关系权重支
    公祖
    公祖
    Lv1
    抽刀断水水更流,举杯销愁愁更愁。
    文章
    4
    粉丝
    0
    获赞
    0