Reflection and Transparency

by Jason Stine

I decided to focus on making realistic reflections for my project, with the effects of transparency also covered. The two concepts I focused on were utilizing the Stencil Buffer/Testing and a form of Environment Mapping.

Here is a sample screenshot taken from the program:


Click here to download and run the executable for Linux (16.1MB compressed zip).

Controls:
- Left click and drag to either rotate the mirrored central object or adjust the camera angle.
- Right click to access the menu. You can change what item you're changing the transparency of, what the type of the central object is, and toggle stencil testing (more on this below).
- Press the F1 key to switch between rotating the central object and moving the camera. (Sorry, weird key for this I know but I ran out of time to change it to something else!)
- Press and hold the Up arrow key to increase the alpha value (make more opaque) of the selected item to change the transparency of.
- Press and hold the Down arrow key to decrease the alpha value of the selected item.

The first step in making this scene a reality was to implement a feature in OpenGL known as "blending". Blending takes multiple colors on the screen and blends them together, which helps to achieve the trick of what appears to be transparency. This feature allows you to specify an alpha value when determining your colors which can then be passed to the blending functions. Below is a screenshot of the mirrored central object, in this case the torus (doughnut), at about 50% transparency:

Both the reflective object's and underlying plane's alpha values can be adjusted. For instance, if you make the plane have 100% transparency, the minimum alpha value, it's invisible, giving us this effect:

Notice that in the above image the objects are still being reflected, but the spinning "pinwheel's" reflection is cut off, because the plane is still there - it's just invisible now. If the transparency was 0%, there'd then be no reflections at all, as the plane would be totally opaque. This brings me to my next point of interest - using the stencil buffer to create reflections. Actually, there are 3 main components being used all at the same time to create this plane: stencil buffering, a clipping plane, and blending.

The stencil buffer is an extra buffer that, according to the official OpenGL specifications, has "applications-specific meanings". It is similar to the depth and color buffers, except the values stored in it don't represent colors or depths, and instead is for the developer to decide what to use it for. In this case, I use the buffer to define bounds for where the reflections are allowed to be seen, for example only through the plane that is drawn "invisibly" to the stencil buffer initially. By disabling the use of the buffer, or also known as stencil testing, the illusion's secret is revealed:

In essence the reflections are really just copies of the "real" objects they represent drawn in a mirrored fashion below the plane, which are then concealed using the stencil buffer which determins from what perspective they'll be viewed. Here's the general command order used to create the illusion of a reflective plane:

1. Enable stencil testing/buffer and turn off drawing to the screen and depth testing.
2. Draw an invisible copy of the plane to this buffer.
3. Set up a clipping plane so the reflective objects don't come "out of" the plane.
4. Mirror the opposite axis and draw the objects representing the reflections under the plane. Also position mirrored lighting for the reflections.
5. Turn stencil testing off and disable the clipping plane, and then draw/position the "real" light.
6. Enable blending and draw the plane again, this time visibly (as the stencil buffer is off) and make it transparent so the reflections can be seen through the plane.
7. Finally, disable blending and draw the "real" objects above the plane.

A couple things that took me a while to figure out was clearing the stencil buffer along with the depth and color buffers in the display function, including specifying it in the display mode initiation command that is called when the program first runs. I found that there's not that many good tutorials out there that show a layman how to set this up, with the exception being the NeHe tutorial (see below). The only thing afterwards that I had to be careful about were the operating system differences.

Lastly, I used "environment mapping" for the central reflective object. Unfortunately, I had an even more difficult time trying to figure out how to do "cube" mapping, which would have made the object perfectly reflective, but I couldn't get it to work, so I had to settle for "sphere" mapping, which only reflects the surrounding NASA space image. This I found had an even worse lineup of tutorials available for implementing this, as I didn't simply just want a "static" cube map - I wanted to create a "dynamic" one, which accurately reflects the scene in real time as the objects/lighting/materials/etc. change around it. I was able to find working examples, but either I couldn't compile and run the code or the code was too complex for me to wrap my head around it.

Basically, to do dynamic cube mapping one must put the camera at the center of the object to be reflected and take 6 snapshots of the scene looking down each axis (positive x, then down negative x, same for y and z) with a field of view of 90 degrees. These 6 images are then mapped immediately onto the object in a similar fashion to sphere mapping (it doesn't have to be a cube, by the way - it can be any object - that's just the name of this technique). This is done each time the scene is rendered, making it the object appear to be reflecting all changes around it in real time almost perfectly. I still hope to implement a dynamic cube map in the future, but I ran out of time for it in this project.

Feel free to contact me regarding any questions you may have of this (if this address still works in the future) at jstine_AT_calpoly.edu (replace _AT_ with @).

References:
- Plane texture: http://www.designifs.com/Pi/Tiles/background.html
- Hubble space image (great for wrapping around 360 degrees!): http://compiz-themes.org/content/show.php/Nebulae?content=72349
- NeHe reflective plane tutorial (Note that this code is for Windows): http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=26
- Sphere mapping tutorial (environment mapping): http://jerome.jouvie.free.fr/OpenGl/Tutorials/Tutorial11.php