为什么 gl.drawElements 需要重新绑定而 gl.drawArrays 不需要?

Why is that gl.drawElements needs rebind while gl.drawArrays doesn't?

大家好,最近在学习webgl

有两个片段可以完成同一件事 - 画一个正方形。一种是对 6 个顶点使用 gl.drawArrays,一种是对 4 个顶点使用 gl.drawElements。

不过我注意到,在使用gl.drawArrays的时候,我们可以先解绑gl.ARRAY_BUFFER再使用,没关系。查看片段。

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); 重新绑定它

这主要在这个答案中解释:

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

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

再次参考这个答案: 以及这个答案: