Frage

What does the "invocations" input layout qualifier of a geometry shader do?

The OpenGL wiki just says that it causes the GS to be executed multiple times for each primitive, and goes on to say that:

The output primitives from instances are ordered by the gl_InvocationID​. So 2 primitives written from 3 instances will create a primitive stream of: (prim0, inst0), (prim0, inst1), (prim0, inst2), (prim1, inst0)

Does each invocation operate on the data of the previous invocation for, say, iteratively refining the geometry? Or is gl_InvocationID supposed to be used in order to do something different in each invocation? Or am I on completely the wrong track?

War es hilfreich?

Lösung

It's instancing within the shader; It works in a manor almost exactly like instancing with glDrawArraysInstanced and such. The same input primitive is processed by num_instances invocations of the GS. Each invocation is completely separate, just like each instance in instanced rendering is completely separate.

The only way to tell the difference between one GS invocation and another for the same primitive input is with the gl_InvocationID. This will be different for each invocation, within the same primitive.

Andere Tipps

The "invocation" is similar to instancing, but has a slightly different use.

Consider the call:

glDrawArray(GL_POINTS, 0, N );

With a shader layout:

 layout (points, invocations=6) in;

Notice the order of invocations given in the OpenGL wiki:
(prim0, invoc0), (prim0, invoc1), (prim0, invoc2), (prim1, invoc0), ... (primN, invoc1), (primN, invoc2)

The purpose of invocation is to process each invocation in order before starting the next primitive. There as some times you need this. However, using invocations is very costly for the GPU, because they must happen in order, and are not easily parallelized.

You can achieve an order-independent invocations by using a uniform buffer.

 const int NUM_INVOC = 6;
   for (int i = 0; i < NUM_INVOC; ++i) {
       glUniform1i( glGetUniformLocation("uiInvocID"), i);
       glDrawArray( GL_POINTS, 0, N );
   }

Then, in the GS use the uniform uiInvocID instead of the gl_InvocationID.
The process order of this will be:
(prim0, invoc0), (prim1, invoc0), (prim2, invoc0), (prim0, invoc1), (prim1, invoc1), (prim2, invoc1), ..

In many cases, the order may not matter. For example, if you are expanding a set of points into a cube, its still perfectly acceptable to render all the top-faces first, then all side, etc. because the Z-buffer will resolve everything. This will be much faster.

Recall, what instancing does is different:
(prim0, inst0), (prim1, inst1), (prim2, inst2) .. (primN, instN)

For regular instancing there is a 1-to-1 relationship between prims and gl_InstanceIDs.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top