【问题标题】:what does instancing do in webgl实例化在 webgl 中做了什么
【发布时间】:2022-01-13 10:16:40
【问题描述】:

我想知道有什么方法可以了解在 webgl 的绘图调用中将调用多少次顶点着色器?因为我想知道实例化真正做了什么,它是否为每个实例调用每个共享顶点?所以它会调用太多时间顶点着色器

【问题讨论】:

    标签: opengl-es webgl shader instances


    【解决方案1】:

    Instancing 为每个实例的每个顶点调用一个顶点着色器。不同之处在于您可以选择 1 个或多个属性,每个实例只前进一次,而不是每个顶点一次。

    通常每个属性为每个顶点增加stride 字节。 stridegl.vertexAttribPointer 的倒数第二个参数。如果stride0,那么WebGL 会根据sizetypegl.vertexAttribPointer 的第二个和第三个参数)为您计算步幅。

    通过实例化,您可以为某些属性调用 gl.vertexAttribDivisor。 0 是默认的正常情况,表示“每个顶点通过缓冲区推进属性一次。 1 表示每个实例将属性推进一次缓冲区。

    这可能是最简单的例子。假设你有一个由 2 个三角形和 6 个顶点组成的四边形

      -1, -1, 
       1, -1,
      -1,  1,
    
      -1,  1,
       1, -1,
      -1, -1,
    

    你还有一个 3 种颜色的缓冲区

      1, 0, 0,
      0, 1, 0,
      0, 0, 1,
    

    你告诉 WebGL 像这样读取四边形位置

    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const size = 2;  // 2 floats per iteration
    const type = gl.FLOAT;
    const normalize = false;
    const stride = 0;  // let WebGL compute the stride based on size and type
    const offset = 0;
    gl.vertexAttribPointer(posLocation, size, type, normalize, stride, offset);
    

    对于您告诉它每个实例使用 1 种颜色的颜色

    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    const size = 3;  // 3 floats per iteration
    const type = gl.FLOAT;
    const normalize = false;
    const stride = 0;  // let WebGL compute the stride based on size and type
    const offset = 0;
    gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
    gl.vertexAttribDivisor(colorLocation, 1);
    

    现在当你像这样打电话给gl.drawArraysInstanced

    const mode = gl.TRIANGLES;
    const first = 0;
    const numVerts = 6;  // 6 verts per quad
    const numInstances = 3;
    gl.drawArraysInstanced(mode, first, numVerts, numInstances);
    

    它将调用您的顶点着色器 3 * 6 次。假设你有

    attribute vec2 position;
    attribute vec3 color;
    

    每次迭代的位置和颜色值将是

     iteration | position | color  | gl_InstanceID | gl_VertexID
     ----------+----------+--------+---------------+------------
         0     |  -1, -1, | 1,0,0  |      0        |    0
         1     |   1, -1, | 1,0,0  |      0        |    1
         2     |  -1,  1, | 1,0,0  |      0        |    2
         3     |  -1,  1, | 1,0,0  |      0        |    3
         4     |   1, -1, | 1,0,0  |      0        |    4
         5     |  -1, -1, | 1,0,0  |      0        |    5
         6     |  -1, -1, | 0,1,0  |      1        |    0
         7     |   1, -1, | 0,1,0  |      1        |    1
         8     |  -1,  1, | 0,1,0  |      1        |    2
         9     |  -1,  1, | 0,1,0  |      1        |    3
        10     |   1, -1, | 0,1,0  |      1        |    4
        11     |  -1, -1, | 0,1,0  |      1        |    5
        12     |  -1, -1, | 0,0,1  |      2        |    0
        13     |   1, -1, | 0,0,1  |      2        |    1
        14     |  -1,  1, | 0,0,1  |      2        |    2
        15     |  -1,  1, | 0,0,1  |      2        |    3
        16     |   1, -1, | 0,0,1  |      2        |    4
        17     |  -1, -1, | 0,0,1  |      2        |    5
    

    请注意,gl_VertexIDgl_InstanceID 仅在 WebGL2 中可用。

    上面的例子并没有那么有用,因为它会直接在另一个上面绘制 3 个三角形。在不同的地方绘制三角形会更有用,就像颜色属性一样,添加一个offset 属性,每个实例有一个偏移量,并将其添加到着色器中的位置。或者更好的是,添加一个mat4 矩阵属性并为每个实例设置一个矩阵。请注意,着色器中的mat4 属性占用 4 个连续的属性位置

    【讨论】:

    • 对不起,我不明白gl.vertexAttribDivisor 只是在webgl2 中吗?我读到了divisor A GLuint specifying the number of instances that will pass between updates of the generic attribute. 如果不止一个会发生什么?
    • gl.vertexAttribDivisor 是 WebGL1 中 ANGLE_instanced_arrays extension 的一部分。指定一个大于 1 的除数只会每 N 个实例继续处理该属性的下一个数据。例如,如果您在上表中将其设置为 2,则前 12 次迭代(前 2 个实例)将读取颜色,后 6 次迭代(最后一个实例)读取绿色
    • 很好的解释。我认为评论中应该是3 floats per iteration - 而不是2,对吧?
    • 正确,已修复,谢谢
    【解决方案2】:

    实例化应该为您节省大量相同网格的绘制调用(glDrawArrays 等)。

    但是,顶点着色器仍然会为每个顶点和每个实例单独运行。它通常应该为每个实例返回不同的值。

    The OpenGL wiki explains this clearly:

    这个想法是,您的顶点着色器具有一些内部机制,用于根据单个数字决定渲染网格的每个实例的位置。也许它有一个表(存储在缓冲区纹理或统一缓冲区对象中),它使用当前顶点的实例编号进行索引,以获得它需要的每个实例的数据。也许它对某些属性使用属性除数,为每个实例提供不同的值。或者它有一个简单的算法,可以根据实例编号计算实例的位置。

    【讨论】:

    • 我一点也不明白,但嘿,这就是我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 2015-07-03
    • 2011-01-17
    • 2018-10-13
    • 2017-04-28
    相关资源
    最近更新 更多