几何着色器调用输入布局限定符

时间:2013-06-05 09:35:19

标签: opengl glsl shader geometry-shader

几何着色器的“调用”输入布局限定符有什么作用?

OpenGL wiki只是说它会导致GS为每个原语执行多次,然后继续说:

  

实例的输出原语由gl_InvocationID排序。因此,从3个实例写入的2个原语将创建一个原始流:(prim0,inst0),(prim0,inst1),(prim0,inst2),(prim1,inst0)

每次调用是否对前一次调用的数据进行操作,例如迭代优化几何?或者是否应该使用gl_InvocationID以便在每次调用时执行不同的操作?或者我完全走错了轨道?

2 个答案:

答案 0 :(得分:2)

它在着色器中实例化;它的工作方式几乎与instancing glDrawArraysInstancednum_instances一样。 GS的gl_InvocationID次调用处理相同的输入原语。每次调用都是完全独立的,就像实例渲染中的每个实例完全分开一样。

对于同一原语输入,告诉一个GS调用和另一个GS调用之间的区别的唯一方法是使用{{1}}。对于每个调用,在同一个原语中,这将是不同的。

答案 1 :(得分:1)

"调用"类似于实例化,但使用方式略有不同。

考虑一下这个电话:

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_InstanceID之间存在一对一的关系。