在绘制过程中绑定VAO之后,是否需要重新绑定IBO?

时间:2019-01-31 04:27:22

标签: graphics webgl webgl2

嗨,我正在学习webgl。

我一直在读一本书Real-Time 3D Graphics with WebGL 2,这里说的是顶点数组对象,使我们可以将一组缓冲区的所有顶点/索引绑定信息存储在单个易于管理的对象中。

它为VAO提供了此示例。

 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 = [
        -0.5, 0.5, 0,
        -0.5, -0.5, 0,
        0.5, -0.5, 0,
        0.5, 0.5, 0
      ];

      // Indices defined in counter-clockwise order
      indices = [0, 1, 2, 0, 2, 3];

      // Create VAO instance
      squareVAO = gl.createVertexArray();

      // Bind it so we can work on it
      gl.bindVertexArray(squareVAO);

      const squareVertexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

      // Provide instructions for VAO to use data later in draw
      gl.enableVertexAttribArray(program.aVertexPosition);
      gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);

      // Setting up the IBO
      squareIndexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

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

    // We call draw to render to our canvas
    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);

      // Bind the VAO
      gl.bindVertexArray(squareVAO);

      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, squareIndexBuffer);

      // Draw to the scene using triangle primitives
      gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

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

    // Entry point to our application
    function init() {
      // Retrieve the canvas
      const canvas = utils.getCanvas('webgl-canvas');

      // Set the canvas to the size of the screen
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      // Retrieve a WebGL context
      gl = utils.getGLContext(canvas);
      // Set the clear color to be black
      gl.clearColor(0, 0, 0, 1);

      // Call the functions in an appropriate order
      initProgram();
      initBuffers();
      draw();
    }

这里的问题是,在将VAO绑定到gl.bindBuffer();后,是否需要draw()

我查看了此链接What are Vertex Arrays in OpenGL & WebGL2?,它说 At draw time it then only takes one call to gl.bindVertexArray to setup all the attributes and the ELEMENT_ARRAY_BUFFER。因此,我认为在将gl.bindBuffer();绑定VAO之后是否不需要draw()? 教科书中的代码会误导人吗?

1 个答案:

答案 0 :(得分:0)

否,您不需要重新绑定缓冲区

ELEMENT_ARRAY_BUFFER绑定是您链接到的答案所指出的当前顶点阵列状态的一部分。

您的示例中的这些行也不相关

initBuffers

  // Clean
  gl.bindVertexArray(null);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

这些行都不是真正需要的。即使不需要,只有第一行具有任何实际点

此行

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

并没有真正做任何事情,因为如上所述ELEMENT_ARRAY_BUFFER状态是当前顶点数组的一部分,因此仅更改gl.bindVertexArray的当前顶点数组就已经改变了绑定。

此行

  gl.bindBuffer(gl.ELEMENT_BUFFER, null);

毫无意义,因为AFAIK几乎没有程序会仅假设当前的ARRAY_BUFFER绑定设置为任何值。他们总是在操作缓冲区之前先绑定一个缓冲区。拥有它还不错,我敢肯定,您可以找到一些令人费解的方法使其变得重要,但在现实生活中,我还没有见过。

这行有一点。

  gl.bindVertexArray(null);

通常将顶点缓冲区与顶点属性分开设置。如果您要绘制的每个物体都制作一个顶点阵列,而您的图案就是这样

  // at init time
  for each thing I plan to draw
    (1) create buffers and fill with positions/normals/texcoords/indices
    (2) create/bind vertex array
    (3) setup attributes and ELEMENT_ARRAY_BUFFER

然后,如果您在第3步之后未绑定null,则第1步将最终更改先前绑定的顶点数组的ELEMENT_ARRAY_BUFFER绑定

换句话说,这行

  gl.bindVertexArray(null);

有一点。不过,这是有争议的。如果您交换了步骤1和2,并将初始化更改为

  // at init time
  for each thing I plan to draw
    (1) create/bind vertex array
    (2) create buffers and fill with positions/normals/texcoords/indices
    (3) setup attributes

然后问题就解决了

draw中存在相同的3行

  // Clean
  gl.bindVertexArray(null);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

他们又没有意义的地方