实例化在webgl中做了什么

MHA*_*A15 2 shader opengl-es instances webgl

我想知道是否可以通过任何方式了解在webgl中的绘制调用中将调用顶点着色器的次数?因为我想知道实例化实际上做了什么,它是否为每个实例调用每个共享顶点?所以它会调用太多时间的顶点着色器

gma*_*man 9

Instancing为每个实例的每个顶点调用一个顶点着色器.区别在于您可以选择1个或多个属性,每个实例仅前进一次,而不是每个顶点前进一次.

通常,每个属性stride为每个顶点提前字节.stride是第二个到最后一个参数gl.vertexAttribPointer.如果stride是,0那么WebGL会根据sizetype(第二个和第三个参数)为你计算一个步幅gl.vertexAttribPointer.

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

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

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

  -1,  1,
   1, -1,
  -1, -1,
Run Code Online (Sandbox Code Playgroud)

您还有3种颜色的缓冲区

  1, 0, 0,
  0, 1, 0,
  0, 0, 1,
Run Code Online (Sandbox Code Playgroud)

你告诉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);
Run Code Online (Sandbox Code Playgroud)

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

gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
const size = 3;  // 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(colorLocation, size, type, normalize, stride, offset);
gl.vertexAttribDivisor(colorLocation, 1);
Run Code Online (Sandbox Code Playgroud)

现在,当你调用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);
Run Code Online (Sandbox Code Playgroud)

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

attribute vec2 position;
attribute vec3 color;
Run Code Online (Sandbox Code Playgroud)

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

 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
Run Code Online (Sandbox Code Playgroud)

请注意,gl_VertexIDgl_InstanceID仅提供WebGL2.

  • `gl.vertexAttribDivisor` 是 WebGL1 中 [`ANGLE_instanced_arrays` 扩展名](https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/) 的一部分。指定一个大于 1 的除数只会每 N 个实例处理一次该属性的下一个数据。例如,如果您在上表中将其设置为 2,则前 12 次迭代(前 2 个实例)将读取颜色,最后 6 次迭代(最后一个实例)将读取绿色 (2认同)