“调用”类似于实例化,但用途略有不同。
考虑调用:
glDrawArray(GL_POINTS, 0, N );
使用着色器布局:
layout (points, invocations=6) in;
注意 OpenGL wiki 中给出的调用顺序:
(prim0, invoc0), (prim0, invoc1), (prim0, invoc2), (prim1, invoc0), ... (primN, invoc1), (primN, invoc2)
调用的目的是在开始下一个原语之前按顺序处理每个调用。有时你需要这个。然而,使用调用对于 GPU 来说代价很高,因为它们必须按顺序发生,并且不容易并行化。
您可以通过使用统一缓冲区来实现与顺序无关的调用。
const int NUM_INVOC = 6;
for (int i = 0; i < NUM_INVOC; ++i) {
glUniform1i( glGetUniformLocation("uiInvocID"), i);
glDrawArray( GL_POINTS, 0, N );
}
然后,在 GS 中使用统一的 uiInvocID 而不是 gl_InvocationID。
其处理顺序将是:
(prim0, invoc0), (prim1, invoc0), (prim2, invoc0), (prim0, invoc1), (prim1, invoc1), (prim2, invoc1), ..
在许多情况下,顺序可能无关紧要。例如,如果您将一组点扩展为一个立方体,首先渲染所有顶面,然后渲染所有侧面等仍然完全可以接受,因为 Z 缓冲区将解决所有问题。这会快得多。
回想一下,实例化的作用是不同的:
(prim0, inst0), (prim1, inst1), (prim2, inst2) .. (primN, instN)
对于常规实例化,prims 和 gl_InstanceIDs 之间存在一对一的关系。