To debug lighting, it is handy to visualize per-vertex normals. Traditionally, one would create a vertex buffer with a bunch of lines representing normals and render this after rendering the mesh itself. This works but it is not nearly as simple, or as cool, as using a geometry shader.

You can write a trivial geometry shader to visualize normals. The shader takes a triangle as input and outputs 3 lines that represent the normal for each vertex. In the first pass, render the mesh as you normally would. In the second, pass enable the geometry shader and render the mesh again. That's it. No extra vertex buffer, just an extra pass.
You'll need a pass-through vertex shader:
varying vec3 normal; void main(void) { gl_Position = gl_Vertex; normal = gl_Normal; gl_FrontColor = gl_Color; }
The vertex shader doesn't transform the vertex, so the geometry shader can operate in world space. The geometry shader computes the normal for each vertex using a length passed in as a uniform.
#version 120 #extension GL_EXT_geometry_shader4 : enable uniform float uNormalsLength; varying in vec3 normal[]; void main() { // assert(gl_VerticesIn == 3); // assert(GL_GEOMETRY_INPUT_TYPE_EXT == GL_TRIANGLES); // assert(GL_GEOMETRY_OUTPUT_TYPE_EXT == GL_LINE_STRIP); // assert(GL_GEOMETRY_VERTICES_OUT_EXT == 6); for(int i = 0; i < gl_VerticesIn; ++i) { gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[i]; gl_FrontColor = gl_FrontColorIn[i]; EmitVertex(); gl_Position = gl_ModelViewProjectionMatrix * (gl_PositionIn[i] + (vec4(normal[i], 0) * uNormalsLength)); gl_FrontColor = gl_FrontColorIn[i]; EmitVertex(); EndPrimitive(); } }
Of course, all this will be encapsulated for Insight3D users. You simply tell the primitive the length of the normals you want to see.
Interesting. Will Point Break require a card with a programmable GS? If not, how do you communicate to users that an extension isn’t supported, and what implies for Point Break functionality?
Also, aren’t lines rendered as thin quads in reality? Why not do this one pass? I hear geometry shader amplification is slow for even moderate amounts of vertices, but I didn’t think that it’d be that bad.
All good questions. Point Break (now called Insight3D, we are all adjusting to the name change) will not require a video card with a programmable GS. Most of the features will run on OpenGL 1.1 or 1.2.
Features that require more recent extensions provide a method called IsSupported. You can call this method before using the feature. For example, the surface mesh primitive is a polygon that conforms to terrain. This requires OpenGL 2.0 so a user should call IsSupported to be confident that the video card has the required extensions.
Other features will have multiple implementations, depending on the extensions supported by the video card. For example, the text rendering algorithm I recently described requires programmable vertex shaders. If they are not available, we plan to fall back to an implementation that does the required computations on the CPU. Similarly, if a programmable GS is not available for rendering normals, the traditional algorithm could be used.
What baseline video card do you expect your application to run on? We always struggle with the decision between writing multiple implementations so we can both take advantage of new cards and support old cards, or writing one implementation that is middle of the road.
You are right, you may be able to do this in one pass. A limitation of the geometry shader is it can only output one type of primitive. In this case, I output GL_LINE_STRIP (GL_LINES is not an option). As you mention, to do this in one pass, we’d have to output triangles and draw the normals as two triangles. I’m sure it is doable, it would just require some math to get the width of the lines to be defined in pixel space instead of world space.
On my GeForce 8, geometry shader amplification is slow. I really wrote this shader to debug code I wrote to compute normals, so performance wasn’t much of a concern. Do you envision using a feature like this for production? Or just debugging?
I’ve done tests on shadow volume amplification using both a geometry shader implementation and a vertex shader implementation that requires more vertex data. I don’t recall the exact results but the vertex shader implementation was something like 25-40% faster even with the extra memory requirements.
I’ve heard from multiple sources that geometry shaders are much faster on more recent video cards. Although, they are not meant for large scale amplification. For example, I’d also like to debug bounding volumes and was thinking of continuously subdividing a tetrahedron in a geometry shader to produce a sphere but I think that will be way too many triangles to output.