Various projects and musings by Mason Smith
Recent developments in GPU technology have allowed rendering effects that were previously only tractable for offline rendering to be used for real time effects via programmable shading. This project demostrates two of the most popular effects: environment mapping and dynamic shadows via shadow mapping.
The demo was written in C++, OpenGL, and SDL. You can download the source code (for both the demo and the offline prefiltering) or a linux executable. All of the models and artwork are included in with both distributions, but you can get a source-only distribution here as well.
The scene consists of three objects and the environment map sphere background. All three objects use the same fragment shader, rtr.frag, which contains the specular, glossy specular, and diffuse environment map lighting computation as well as shadow mapping. The shadows come from two lights rotating around the scene at different speeds.
The OpenGL model-view matrix was used only for the camera space transformation. A separate uniform shader variable was set for the object transformation on a per-vertex basis. This way, the fragment shader is completely independent of local object transformations.
Each object in the scene has its own material, consisting of the portion of light reflected through diffuse, specular, and glossy specular reflections.
Part of the lab was to demonstrate a simple effect that is difficult or impossible to do without vertex or fragment shaders. In my demo, the torus is created from a 2D grid of xy points. The torus is animated by its object transformation as well as the inner and outer radii. The normals are generated on-the-fly in the vertex shader, using the two tangent vector Du(p) and Dv(p). Furthermore, the diffusely-reflected color of the torus is at a point is determined by the camera-space normal at each point.
Note: In this section, all images are rendered without environment lighting to highlight the shadow mapping results.
I implemented percentage closer filtering using a brute-force 16-pixel method, as in [Bunnell]. Using a broader sampling neighborhood, area lights can be simulated as well.
With shadow mapping, the scene is rendered from the light's point of view. The z-buffer is then used as a projective onto the scene. At each point, the distance from the point to the light is compared to the stored depth, and points with further distances are not illuminated by the light. Though my implementation on uses point lights, one can use the technique with directional lights as well (by rendering with an orthogonal projection).
To prevent z-fighting in light space, when rendering from the lights we only render the back faces. This way, the closest front-facing lights are always lit, and we can use a "greater than or equal to test" without noticeable artifacts.
In addition to these, you can download a video demo of the program. (There are a couple of... imperfections, but nothing too distracting. The demo is different from the YouTube video below, but it demonstrates the same features.