WebGL2系列之頂點數組對象

使用了頂點緩衝技術後,繪製效率有了較大的提高。可是還有一點不盡如人意,那就是頂點的位置座標、法向量、紋理座標等不一樣方面的數據每次使用時須要單獨指定,重複了一些沒必要要的工做。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的代碼很相似,下面是一個三角相關數據定義的代碼code

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);
    相關文章
    相關標籤/搜索