【问题标题】:Why is that gl.drawElements needs rebind while gl.drawArrays doesn't?为什么 gl.drawElements 需要重新绑定而 gl.drawArrays 不需要?
【发布时间】:2019-01-29 17:17:32
【问题描述】:

大家好,这些天我一直在学习 webgl。

有两个 sn-ps 完成同样的事情——画一个正方形。一种是使用 gl.drawArrays 来处理 6 个顶点,一种是使用 gl.drawElements 来处理 4 个顶点。

但是我注意到在使用gl.drawArrays的时候,我们可以在使用之前解绑gl.ARRAY_BUFFER,没关系。请参阅 sn-ps。

function initBuffers() {
      /*
        V0                    V3
        (-0.5, 0.5, 0)        (0.5, 0.5, 0)
        X---------------------X
        |                     |
        |                     |
        |       (0, 0)        |
        |                     |
        |                     |
        X---------------------X
        V1                    V2
        (-0.5, -0.5, 0)       (0.5, -0.5, 0)
      */
      const vertices = [
        // first triangle (V0, V1, V2)
        -0.5, 0.5, 0,
        -0.5, -0.5, 0,
        0.5, -0.5, 0,

        // second triangle (V0, V2, V3)
        -0.5, 0.5, 0,
        0.5, -0.5, 0,
        0.5, 0.5, 0
      ];

      // Setting up the VBO
      squareVertexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(program.aVertexPosition);
      // Clean
      gl.bindBuffer(gl.ARRAY_BUFFER, null);
    }

function draw() {
      // Clear the scene
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

      gl.drawArrays(gl.TRIANGLES, 0, 6);

      // Clean
      gl.bindBuffer(gl.ARRAY_BUFFER, null);
    }

initBuffers()draw() 之前被调用。注意这里我在调用gl.drawArrays之前已经解除绑定gl.ARRAY_BUFFER,它成功绘制了正方形。

但是,当使用 gl.drawElements 时,我必须确保 gl.ELEMENT_ARRAY_BUFFER 当前绑定到正确的索引。例如

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

如果我像使用gl.drawArrays 一样使用gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);,我必须在调用gl.drawElements 之前使用gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer); 重新绑定它。

【问题讨论】:

    标签: javascript webgl webgl2


    【解决方案1】:

    这个答案主要解释了这一点:https://stackoverflow.com/a/27164577/128511

    简短版本是gl.drawArrays 仅使用属性。当您调用gl.vertexAttribPointer 时,属性具有绑定到它们的缓冲区。无论绑定什么缓冲区,在您调用 gl.verexAttribPointer 时都会将 gl.ARRAY_BUFFER 复制到该属性的状态中。

    属性本身是当前顶点数组对象 (VAO) 的状态,当前 ELEMENT_ARRAY_BUFFER 也是如此。 VAO 是 WebGL1 中的可选扩展,也是 WebGL2 的标准部分。

    再次参考这个答案:https://stackoverflow.com/a/27164577/128511 和这个答案:https://stackoverflow.com/a/50257695/128511

    【讨论】:

    • 您好,感谢您的回复。我不完全确定您所说的 Whatever buffer was bound do gl.ARRAY_BUFFER at the time you call gl.verexAttribPointer is copied into the state of that attribute. 是什么意思,但是我查看了您发布的那些链接,我觉得我已经掌握了窍门。如果我错了,请纠正我。 gl.drawArrays 不需要重新绑定的原因是因为gl.vertexAttribPointer 在内部存储了 arrayBuffer 以便我们可以使用。另一方面,gl.drawElements 具有全局 elementArrayBuffer,所以如果我们之前解绑它,我们必须重新绑定它。
    • 更正gl.drawArrays。对于gl.drawElements,elementArrayBuffer 是当前vertexArray 状态的一部分。在 WebGL1 中只有一个全局 vertexArray,除非您启用 OES_vertex_array 扩展。在 WebGL2 中,您创建的顶点数组数量与您创建的数量一样多(请参阅gl.createVertexArraygl.bindVertexArray)。一个顶点数组包含所有的属性状态 elementArrayBuffer 状态
    • 感谢您的回复!既然我们在webgl2中可以有多个VAO来存储属性状态和elementArrayBuffer状态,那我们是否需要区分哪个VAO存储哪个属性状态和哪​​个elementArrayBuffer状态呢?有没有办法检查?
    猜你喜欢
    • 2018-03-18
    • 2018-07-30
    • 2011-06-18
    • 2021-04-13
    • 1970-01-01
    • 2016-09-13
    • 2016-01-10
    • 2023-03-27
    • 1970-01-01
    相关资源
    最近更新 更多