我想知道是否可以通过任何方式了解在webgl中的绘制调用中将调用顶点着色器的次数?因为我想知道实例化实际上做了什么,它是否为每个实例调用每个共享顶点?所以它会调用太多时间的顶点着色器
答案 0 :(得分:7)
Instancing为每个实例的每个顶点调用一个顶点着色器。区别在于您可以选择一个或多个属性,每个实例仅前进一次,而不是每个顶点前进一次。
通常,每个属性为每个顶点提前stride
个字节。 stride
是gl.vertexAttribPointer
的最后一个参数的第二个。如果stride
为0
,则WebGL会根据size
和type
(gl.vertexAttribPointer
的第2和第3个参数为您计算一个步幅。
通过实例化,您可以针对某些属性调用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; // 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);
现在,当你像这样打电话给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_VertexID
和gl_InstanceID
仅适用于WebGL2。
答案 1 :(得分:1)
实例化应该可以为同一个网格节省大量的绘制调用(glDrawArrays
等)。
但是,顶点着色器仍将针对每个顶点和每个实例单独运行。通常应该为每个实例返回不同的值。
The OpenGL wiki explains this clearly:
这个想法是你的顶点着色器有一些内部机制,用于根据单个数字决定渲染网格的每个实例的位置。也许它有一个表(存储在缓冲区纹理或统一缓冲区对象中),它使用当前顶点的实例编号进行索引,以获得所需的每实例数据。也许它对某些属性使用属性除数,它为每个实例提供不同的值。或者它可能有一个简单的算法,用于根据实例编号计算实例的位置。