CS481(Topics in Computer Graphics), taught by Chris Hartman, was the only graphics class I had the opportunity to take at UAF. Because graphics are my primary programming hobby, it was a lot of fun. We spent on a lot of time on ray tracing, iterated function systems, and fractals, all topics I hadn't looked into before. We also got the chance to write some demos, two of which are chronicled below.
For our final project, we were given the opportunity to create a demo of our choice. I wanted to try creating some small-scale water, like a pond. The techniques I used were pretty standard, but I think the result is beautiful, especially in motion.
Take a look at the slides used during my final presentation for a brief overview of how the water works with some explanatory pictures.
The water is just a quad with a fancy shader and a normal map used to perturb the reflection/refraction map. The normal map is computed on the GPU using a simple discretization of the wave equation. Setting a pixel of the heightmap to, say, 0, will propagate a mostly circular wave in subsequent iterations. This model allows for waves to bounce off irregular boundaries realistically. For being so simple, it works brilliantly. I believe this approach is used in a few games, like The Bard's Tale for X-Box, but it is used at a low resolution and only for the trails following player movement.
The demo has a 'tracing' mode, allowing you to drag the mouse around, creating water trails. It also has a few settings for automatic water perturbation, like bubble jet and raindrops.
The reflection consists of two textures: the cube map and a planar reflection of the terrain. The problem with planar reflections is that it is impossible to get those sparkly sun reflections when the sun is behind the camera. A good plan for a game with a real-time sky would be to lazily update a cube map, use that for the sky, and render a planar reflection for everything else. The planar reflection is rendered with alpha to determine where the cube map should take over.
Refraction is handled the standard way - render the stuff below the water into a texture and perturb the texture coordinates in a separate pass. One good idea from the Crytek guys in GPU Gems 2 is to render the whole scene once into a texture and use it for both the final frame and refraction map.
I also take the water heightmap and use that to fake caustics on the terrain. It is surprisingly convincing, and cheap!
We discussed a few shadow techniques in CS481. I had already implemented shadow maps, and was excited to hear about shadow volumes. Although the assignment didn't call for it, I had to implement them and see for myself what they're like.
The demo consists of a reflective platform out in space, an articulated lamp with 4 rotatable joints, a single OBJ model, and shadows.
It didn't take long for shadow volumes to leave a bad taste in my mouth. It's taxing on the CPU to generate the volumes, fill-rate intensive to render the shadows, and difficult to make the shadows soft. You can always tell when a game uses shadow volumes - turning them on halves your framerate. I'm glad that fad is over... every modern game is using shadow maps. With multiple shadow maps of varying resolution, or by using one of the many perspective shadow map techniques, you can avoid aliasing and have cheap, beautiful soft shadows.