Reputation: 437
I want to draw multiple fans with a GS. Each fan should billboard to the camera at each time, which makes it necessary that each vertex is multiplied with MVP matrix. Since each fan is movable by the user, I came up with the idea to feed the GS with the position.
The following geometry shader works as expected with points as in and output:
uniform mat4 VP;
uniform mat4 sharedModelMatrix;
const int STATE_VERTEX_NUMBER = 38;
layout (shared) uniform stateShapeData {
vec2 data[STATE_VERTEX_NUMBER];
};
layout (triangles) in;
layout (triangle_strip, max_vertices = 80) out;
void main(void)
{
int i;
mat4 modelMatrix = sharedModelMatrix;
modelMatrix[3] = gl_in[0].gl_Position;
mat4 MVP = VP * modelMatrix;
gl_Position = MVP * vec4( 0, 0 , 0, 1 );
EmitVertex(); // epicenter
for (i = 37; i >= 0; i--) {
gl_Position = MVP * vec4( data[i], 0, 1 );
EmitVertex();
}
gl_Position = MVP * vec4( data[0], 0, 1 );
EmitVertex();
}
I tried to run this with glDrawElements
, glDrawArrays
and glMultiDrawArrays
. None of these commands draws the full fan. Each draws the first triangle filled and the remaining vertices as points.
So, the bottom question is: Is it possible to draw a fan with GS created vertices and how?
Upvotes: 2
Views: 3128
Reputation: 43319
Outputting fans in a Geometry Shader is very unnatural as you have discovered.
You are currently outputting the vertices in fan-order, which is a construct that is completely foreign to GPUs after primitive assembly. Fans are useful as assembler input, but as far as output is concerned the rasterizer only understands the concept of strips.
To write this shader properly, you need to decompose this fan into a series of individual triangles. That means the loop you wrote is actually going to output the epicenter on each iteration.
void main(void)
{
int i;
mat4 modelMatrix = sharedModelMatrix;
modelMatrix[3] = gl_in[0].gl_Position;
mat4 MVP = VP * modelMatrix;
for (i = 37; i >= 0; i--) {
gl_Position = MVP * vec4( 0, 0 , 0, 1 );
EmitVertex(); // epicenter
gl_Position = MVP * vec4( data[i], 0, 1 );
EmitVertex();
gl_Position = MVP * vec4( data[i-1], 0, 1 );
EmitVertex();
// Fan and strip DNA just won't splice
EndPrimitive ();
}
}
You cannot exploit strip-ordering when drawing this way; you wind up having to end the output primitive (strip) multiple times. About the only possible benefit you get to drawing in fan-order is cache locality within the loop. If you understand that geometry shaders are expected to output triangle strips, why not order your input vertices that way to begin with?
Upvotes: 3