Geometry shaders part 1

New in OpenGL 3.2 is so called geometry shaders, if you don’t know what they are then what the essentially do is allow you to create new or duplicate geometry. Like instead of drawing a bunch of cubes one after another you could just render a point cloud and let the geometry shader “upgrade” them to cubes, which is probably how i would render minecraft if i where it’s creator, which i would if i had a hat half as awesome as notch does.

Anyway i plan of showing a few things you can do with this, first up are simple billboarded particles just to show how it’s done and what you need, and i am only going to be concerned with the actual code needed for you to include this in your project, and not the main render loop since it’s basically the same as before, what im using in this example is basically the third openGL 3 lesson but with a point cloud instead of a cube, so get that in order before we start.

The first function we need to add is void loadGShade(char filename[160]), it’s the same as the other two but uses the word Geometry instead of Fragment or Vertex, except for something we add in the end if we manage to load it

usegeoshader=1;

it later makes sure we can load shaders without having to have a geometry shader, it’s purely for convenience.

the second function we need to change is compileShaders, now there are a lot of changes to it so it’s best if i post the entire thing but it’s pretty straight forward

 [stextbox id="grey"]void compileShaders(void)
{

 int compiled = 0;
 int linked   = 0;
 char str[4096];

 useshader=1;

 ProgramObject       = glCreateProgramObjectARB();
 VertexShaderObject = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
 FragmentShaderObject = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
 if(usegeoshader)    GeometryShaderObject = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT);

 glShaderSourceARB(VertexShaderObject, 1, (const char **)&VertexShaderSource, NULL);
 glShaderSourceARB(FragmentShaderObject, 1, (const char **)&FragmentShaderSource, NULL);
 if(usegeoshader)
     glShaderSourceARB(GeometryShaderObject, 1, (const char **)&GeometryShaderSource, NULL);

 delete[] VertexShaderSource;
 delete[] FragmentShaderSource;
 if(usegeoshader)    delete[] GeometryShaderSource;

 // Compile the vertex and fragment shader, and print out the
 glCompileShaderARB(VertexShaderObject);
 glGetObjectParameterivARB(VertexShaderObject,GL_OBJECT_COMPILE_STATUS_ARB, &compiled);

 if (!compiled) {

 glGetInfoLogARB( VertexShaderObject, sizeof(str), NULL, str );
 MessageBox( NULL, str, "vertex Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
 useshader=0;
 return;
 }

 glCompileShaderARB(FragmentShaderObject);
 glGetObjectParameterivARB(FragmentShaderObject,GL_OBJECT_COMPILE_STATUS_ARB, &compiled);

 if (!compiled) {
 glGetInfoLogARB( FragmentShaderObject, sizeof(str), NULL, str );
 MessageBox( NULL, str, "Fragment Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
 useshader=0;
 return;
 }

 if(usegeoshader){
 glCompileShaderARB(GeometryShaderObject);
 glGetObjectParameterivARB(GeometryShaderObject,GL_OBJECT_COMPILE_STATUS_ARB, &compiled);

 if (!compiled) {
 glGetInfoLogARB( GeometryShaderObject, sizeof(str), NULL, str );
 MessageBox( NULL, str, "Geometry Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
 useshader=0;
 return;
 }
 }

 glAttachObjectARB(ProgramObject,VertexShaderObject);
 glAttachObjectARB(ProgramObject,FragmentShaderObject);
 if(usegeoshader)    glAttachObjectARB(ProgramObject,GeometryShaderObject);

 glDeleteObjectARB(VertexShaderObject);
 glDeleteObjectARB(FragmentShaderObject);
 if(usegeoshader)    glDeleteObjectARB(GeometryShaderObject);

 if(usegeoshader) { 
        glProgramParameteriEXT(ProgramObject,GL_GEOMETRY_INPUT_TYPE_EXT,GL_POINTS);
        glProgramParameteriEXT(ProgramObject,GL_GEOMETRY_OUTPUT_TYPE_EXT,GL_TRIANGLE_STRIP);
 }

 int temp;
 if(usegeoshader)    glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT,&temp);
 if(usegeoshader)    glProgramParameteriEXT(ProgramObject,GL_GEOMETRY_VERTICES_OUT_EXT,temp);

 glLinkProgramARB(ProgramObject);
 glGetObjectParameterivARB(ProgramObject, GL_OBJECT_LINK_STATUS_ARB,    &linked);

 if (!linked) {
 MessageBox (HWND_DESKTOP, "can't link shaders", "Error", MB_OK | MB_ICONEXCLAMATION);
 useshader=0;
 return;
 }

 return;
}[/stextbox]

that is save for the lines

 [stextbox id="grey"]if(usegeoshader) {
 glProgramParameteriEXT(ProgramObject,GL_GEOMETRY_INPUT_TYPE_EXT,GL_POINTS);
 glProgramParameteriEXT(ProgramObject,GL_GEOMETRY_OUTPUT_TYPE_EXT,GL_TRIANGLE_STRIP);
 }[/stextbox]

what they do is to dictate what the input and output is in what type of format, in this case i input points and output quads, this is also possible to do within the shader, but more about that in the next tutorial

Last step is to create the actual geometry shader

 [stextbox id="grey"]#version 150
in vec4 pos[];
out vec4 posx;

void main( void )
{
posx=pos[0].xyzw;
float s=min(0.1/(abs(pos[0].z)*0.5),0.1);  //scale
gl_Position = pos[0].xyzw+vec4(s,s*1.3,0.0,0.0);
EmitVertex();
gl_Position = pos[0].xyzw+vec4(s,-s*1.3,0.0,0.0);
EmitVertex();
gl_Position = pos[0].xyzw+vec4(-s,s*1.3,0.0,0.0);
EmitVertex();
gl_Position = pos[0].xyzw+vec4(-s,-s*1.3,0.0,0.0);
EmitVertex();

EndPrimitive();
}[/stextbox]

So let me explain a little, on the second row you see that pos is an array even though we didn’t specify this, it’s like this because if we would send a primitive like a triangle the first vertex would occupy pos[0] the second pos[1] and so on, it’s like this with all of the input variables.

EmitVertex() is a special function unique for the geometry shader it takes all the out variabels plus the special gl_Position variable and sends it to a buffer, it works just like the vertex shader up to this point, but the difference is that here you can do it several times and when you have completed the specified primitive you just call EndPrimitive(); to begin rendering.

in this specific example we create quads by emitting the same vertex four times with a bit of offset and scaling added to it, well technically it’s triangle strips since only points, linestrips and triangle strips are alowed, but it can be worked around.

Before geomery shader

Before geomery shader

Before geomery shader

after geometry shader

 

 

 

 

 

 

 

 

Download the source for MS Visual C++ 6 here
Download the source for MS Visual C++ 2008 here

Part 2 | Part 3


No Comments

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

*


WordPress Themes