PDA

View Full Version : Creating Impostor Quad with Geometry Shader



Ottaz
11-30-2010, 10:59 AM
I'm trying to create a program such that my shader receives a position in world space and draws an impostor at that position.

The geometry shader is supposed to take the single vertex position and create a quad, and the fragment shader then textures the quad.

The shaders work (in theory), because I can see the result in my shader builder (XCode's OpenGL Shader Builder). Of course, when I load them into my program, nothing shows.

I'm pretty sure it's due to the information being received (or not) from the main program. May someone take a look and tell me what I should or shouldn't have order to get it to work, please?

I've posted relevant code below...

<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. (Vertex Shader) <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">
uniform vec4 position;

void main()
{
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewMatrix * position;
}
[/QUOTE]</div>

<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. (Fragment Shader) <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">
uniform sampler2D tex;

void main()
{
vec4 color = texture2D(tex, gl_TexCoord[0].xy);
float x = color.x;
float y = color.y;
float zz = (x + y) / 2.0;

if (zz <= 0.2)
discard;

gl_FragColor = gl_Color * color;
}
[/QUOTE]</div>

<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. (Geometry Shader) <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">
#extension GL_EXT_geometry_shader4 : enable

uniform float size;

void main()
{
gl_TexCoord[0] = gl_TexCoordIn[0][0];
gl_FrontColor = gl_FrontColorIn[0];

// Vertex 1
gl_TexCoord[0].st = vec2(0.0,1.0);
gl_Position = gl_PositionIn[0];
gl_Position.xy += vec2(-size, -size);
gl_Position = gl_ProjectionMatrix * gl_Position;
EmitVertex();

// Vertex 2
gl_TexCoord[0].st = vec2(0.0,0.0);
gl_Position = gl_PositionIn[0];
gl_Position.xy += vec2(-size, size);
gl_Position = gl_ProjectionMatrix * gl_Position;
EmitVertex();

// Vertex 3
gl_TexCoord[0].st = vec2(1.0,1.0);
gl_Position = gl_PositionIn[0];
gl_Position.xy += vec2(size, -size);
gl_Position = gl_ProjectionMatrix * gl_Position;
EmitVertex();

// Vertex 4
gl_TexCoord[0].st = vec2(1.0,0.0);
gl_Position = gl_PositionIn[0];
gl_Position.xy += vec2(size, size);
gl_Position = gl_ProjectionMatrix * gl_Position;
EmitVertex();

EndPrimitive();
}
[/QUOTE]</div>

<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. (Relevant main code) <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">
// Geometry shader info in create shader program function
...
glProgramParameteriEXT(p, GL_GEOMETRY_INPUT_TYPE_EXT, GL_POINTS);
glProgramParameteriEXT(p, GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP);
glProgramParameteriEXT(p, GL_GEOMETRY_VERTICES_OUT_EXT, 4);
...

// Impostor function
void impostor(){

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, impostortexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glUseProgram(p);
glUniform1i(glGetUniformLocation(p, "tex"), 0);
glUniform1i(glGetUniformLocation(p, "size"), 2);
glUniform3fv(glGetUniformLocation(p, "position"), 1, origin);

// start - what do I put here?
glBegin(GL_POINTS);
glVertex3fv(origin);
glEnd();
// stop - what do I put here?

glUseProgram(0);

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
[/QUOTE]</div>

aqnuep
11-30-2010, 12:07 PM
As I see you put your object to the origin. This will not be visible if you use e.g. gluPerspective.
You should put the object to position (0,0,-2) and try it again.
BTW, why are you passing the vertex position as a uniform variable? You should take it from vertex attribute.

david_f_knight
11-30-2010, 02:32 PM
I have a comment about your geometry shader. Disclaimer: I only use OpenGL 4 so I don't know the particulars of older versions such as you are using.

In OpenGL 4, at least, the only primitives geometry shaders can process (input or output) are points, lines, and triangles. Quads, as your geometry shader outputs, are not permitted. In OpenGL 4, you must provide an input layout qualifier and an output layout qualifier with which to specify the primitive type input and output. Your geometry shader has no layout qualifiers.

Incidentally, the geometry shader is a core part of later versions of OpenGL (so no need for extensions). Is there any particular reason you are using such an old version of OpenGL?

aqnuep
12-01-2010, 01:19 AM
He is using the EXT version of the geometry shader extension. It uses API calls to setup the primitive type and he is actually using triangle strips, not quads. He draws a quad using a triangle strip with 4 points.

Here is how he sets the output layout:


glProgramParameteriEXT(p, GL_GEOMETRY_INPUT_TYPE_EXT, GL_POINTS);
glProgramParameteriEXT(p, GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP);
glProgramParameteriEXT(p, GL_GEOMETRY_VERTICES_OUT_EXT, 4);

As he said, he is using XCode so most probably he develops on MacOSX and it most probably does not support the ARB version of the geometry shader extension as Mac OpenGL is stuck at version 2.1.

Zenja
12-01-2010, 05:15 AM
Just to throw a bone into this conversation, but aren't Point Sprites what the original poster is asking for - ie. they draw a textured quad facing the camera given a single vertex position.

aqnuep
12-01-2010, 07:54 AM
Similar, but not the same. There are at least two key differences:

1. Point sprites have severe size restrictions (especially on NVIDIA hardware AFAIK).
2. You cannot create such billboards with point sprites (at least not directly) that are facing the camera but are rotated around the Z axis (e.g. billboard of a tree that has to has its trunk always perpendicular to the horizon even if the camera is bent).

Ottaz
12-01-2010, 11:23 AM
Agnuep is correct, I am limited to using the EXT version of the geometry shader due to my installed version of OpenGL and the fact that I (ideally) need to be able to run the program on a campus windows pc that also has an old version of OpenGL.

@Agnuep - When I change the variable type of position to 'attribute', I can no longer see the impostor in my shader builder.

I make the change in the main program in the impostor function like this to facilitate the attribute variable but it's not working -


...
glBegin(GL_POINTS);
glVertexAttrib3fv(glGetAttribLocation(p, "position"), myPoint);
glVertex3fv(myPoint);
glEnd();
...


It shouldn't matter whether 'myPoint' is the world space origin or 3 units back from the world space origin as long as I put my camera in a world space position that will allow me to see it. I'm obviously not going to place the camera at the same world space position as the impostor.

Again, this is the idea...
The fragment shader is texturing a quad created by the geometry shader. The geometry shader uses a single vertex to make the quad, and this vertex is in world space and read in via the vertex shader.

That is all there is to the algorithm. All this shader program is supposed to do is create an impostor at that single vertex position.

I think the problem I am having lies with how the position is interpreted by each shader file. I don't think the geometry shader knows that gl_PositionIn is the 'position' passed to the vertex shader.

I have had it with researching information on google, I'm spending way too long trying to find info, so please assist if u can, any advice (besides use google!) may be helpful.

aqnuep
12-01-2010, 03:10 PM
For me the rest seems good. I don't know what else can be the problem (however, I never used the EXT version of geometry shader and I never use gl_PositionIn so not sure. Maybe if you use some other varying to pass the modelview space vertex from the vertex shader to the geometry shader can help, at least it won't rely on the gl_PositionIn built-in. Can you try it that way? You are not obligated to use gl_Position in vertex shader if you have a geometry shader so you can safely do it.

Dark Photon
12-01-2010, 07:31 PM
1. Point sprites have severe size restrictions (especially on NVIDIA hardware AFAIK).
Not last time I checked. In fact, quite the opposite on NVidia, if you use gl_PointSize (GLSL) with GL_VERTEX_PROGRAM_POINT_SIZE. See:

* Blowing up Pointsizes ehem... (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&amp;Number=266636#Post2666 36)
* Is point sprites a myth ? (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&amp;Number=270493#Post2704 93)

aqnuep
12-02-2010, 01:20 AM
Ah, thanks for the clarification. I tried it only several years ago and at that time I remember there were such restrictions like on ATI the max point size was about 8192 and on NVIDIA it was about 512 or so. That's why I said this.

BTW, one more limitation of point sprites:
If your point sprite center is not on screen (it is clipped), then the whole point sprite billboard is not rendered, even though it would be partially visible. This does not happen with geometry shader generated billboards.

Dark Photon
12-02-2010, 06:15 AM
BTW, one more limitation of point sprites:
If your point sprite center is not on screen (it is clipped), then the whole point sprite billboard is not rendered, even though it would be partially visible. This does not happen with geometry shader generated billboards.
Actually on NVidia with VERTEX_PROGRAM_POINT_SIZE, they're clipped as a quads, like you'd want them to be, rather than as a single point.

aqnuep
12-02-2010, 07:05 AM
Actually on NVidia with VERTEX_PROGRAM_POINT_SIZE, they're clipped as a quads, like you'd want them to be, rather than as a single point.

One thing "you'd want them to be" and another thing what the OpenGL specification says. The spec clearly says that point sprites are clipped in the same way as points.

Dark Photon
12-02-2010, 05:38 PM
Actually on NVidia with VERTEX_PROGRAM_POINT_SIZE, they're clipped as a quads, like you'd want them to be, rather than as a single point.One thing "you'd want them to be" and another thing what the OpenGL specification says. The spec clearly says that point sprites are clipped in the same way as points.
True. I've always been puzzled by that particular spec requirement. When would you really want that behavior? No question that (if speced to clip as quads) doing point sprites this way is easier than adding a geometry shader.

Alfonse Reinheart
12-02-2010, 06:01 PM
It's legacy. The original point-sprite logic, back from the early GeForce era, was really hardware-driven. Points had a maximum size based on the hardware. And they had to be clipped based on the point value because that's what the hardware did.

Relaxing the size restriction was easy enough, since it is a queriable value: just make it a really big number. Relaxing the clipping however would break backwards compatibility. And we can't have that, now can we? ;)

aqnuep
12-03-2010, 01:20 AM
Assuming that point sprites are just points as any other points are, clipping the point position is logical.

Also, point sprites can be used to draw e.g. sparkles and light glow and in that case if you don't see the source of the sparkle/light glow then you won't see anything, so it is logical to use point sprites for that. Similar technique was used in many car racing game titles (I don't want to advertise them) to render the light glow of the headlights.