Snowfall

This demo uses the new OpenGL geometry shader extension in conjunction with instancing to render thousands of uniquely shaped snowflakes constructed on the GPU. A depth-of-field effect is added by blurring the image per-pixel, depending on the depth buffer value.

Downloads:

Source:   Snowfall.zip   196kB

References:

GLSL Geometry Shaders - Mike Bailey, OSU
EXT_geometry_shader4 - OpenGL Specification

Details:

These lines are required to set up the geometry shader:

#version 120 
#extension GL_EXT_geometry_shader4 : enable

Within the geometry shader, the EmitVertex() and EndPrimitive() calls are
used to pass geometry on to the next stage in the pipeline:

gl_Position = gl_ProjectionMatrix * pt1;
EmitVertex();
gl_Position = gl_ProjectionMatrix * pt2;
EmitVertex();
// ...
EndPrimitive();


Some extra setup code is required in the host program to compile and link the geometry shader. The subtle gotcha here is that you have to set the input and output type parameters after program creation time and before link time:

GLuint geomshader = loadShaderFile(geomfile, GL_GEOMETRY_SHADER_EXT);
glCompileShader(geomshader);
glAttachShader (program, geomshader);

glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT , GL_TRIANGLES);
glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLES);

int temp;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &temp);
// Any higher than 256 and this doesn't work on my GTX 285
glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, 256);

glLinkProgram(program);

To enable instanced rendering in the vertex shader, we add these lines:
#version 120
#extension GL_EXT_gpu_shader4 : enable

attribute vec4 in_Position;
attribute vec4 in_Rotation;
attribute vec4 in_Params;

Then we plug in our per-instance attribute arrays as follows in the host code:
GLint attloc3 = glGetAttribLocation(m_program, "in_Params");
glBindBuffer(GL_ARRAY_BUFFER, m_paramVBO);
glEnableVertexAttribArray(attloc3); 
glVertexAttribPointer((GLuint)attloc3, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribDivisor(attloc3, 1);
//...
glDrawElementsInstancedEXT(GL_TRIANGLES,
                           3*12, // #verts in hex tris
                           GL_UNSIGNED_INT,
                           s_Hextris,
                           m_nFlakes);