Real Time Shadows

Shadows are an important part of any scene. They give add realism and help give the viewer a sense of the depth of the objects in the scene. With non-real time rendering techniques such as , adding shadows is trivial. Real time rendering of dynamic shadows is much more challenging. It is only fairly recently that video hardware has become powerful enough to calculate shadows accurately and at interactive rates.

There are two common techniques for rendering dynamic shadows in real time. They are shadow mapping and stencil shadow volumes. In this talk I will give an overview of each technique.

Shadow Mapping

I will start my discussion with shadow mapping because it is the simpler of the two techniques. Shadow mapping is an image based technique. The geometry of the shadow is stored in a texture, which is the shadow map.

To understand how shadow maps work, we first have to understand how the depth buffer works. Every time a fragment (pixel) is rendered to the frame buffer, the pixel’s color is written to the frame buffer and its distance from the camera is also written to a non- visible buffer called the depth buffer. If another fragment is going to be drawn in the same spot, its depth is compared to the depth of the existing fragment. This is called the depth test. If the new fragment’s depth is smaller (its closer to the camera) the depth test passes and the fragment is written. If the fragment’s depth is larger that the existing depth, the depth test fails and the fragment is discarded.

Consider placing the camera at the location of a spotlight shining down on a scene. When the scene is rendered from this perspective, any object occluded from the light will have a depth value greater that the depth stored in the depth buffer. Surfaces visible to the light will have depth values less that or equal to the one in the depth buffer. The depth buffer can be used to partition the scene into shadowed and non shadowed regions. This depth buffer is the shadow map.

This image taken from reference [1] shows the scene rendered from the camera’s position (left), the light’s position (center) and the depth buffer from the lights position (right).

Here is how to use the shadow map to render the scene:

1. First render the scene with only ambient and non-shadow casting lights. 2. For each shadow casting light 3. Render the scene from the light’s perspective 4. Store the depth buffer in a texture (the shadow map) 5. With additive blending, render the scene with only the current light enabled. When rendering, also transform each vertex into light space. In addition to the standard depth test, use the light space coordinates to also perform a depth test against the shadow map. Discard the fragment if it fails either test.

Problems with Shadow Maps Shadow maps are relatively easy to implement, but have some shortcomings. The shadow maps can consume a large amount of video memory. Further more, aliasing is likely to occur if the shadow map is spread over a very large area, or if there objects that are small or have detailed geometry.

This image taken from reference [3] shows aliasing when the shadow map is stretched over too large an area. Stencil Shadows

Stencil shadows take another approach to rendering shadows. Shadow volumes are computed and used to determine whether a fragment is shadowed or not. To understand stencil shadows, we have to understand the .

The stencil buffer is similar to the depth buffer. It is a non-visible integer buffer. Typically this buffer is 8 bits per pixel. When rendering, a stencil write operation can be defined that will modify this buffer every time a fragment is written. Also, a stencil test can be defined that will cause a fragment to be discarded based upon the value stored in the stencil buffer.

To make stencil shadows work, every shadow casting object in a scene must have a shadow volume. I’ll discuss how these volumes are computed later. Stencil shadow casting uses the stencil buffer to count the number of times a ray extending from the camera enters and exits the shadow volume.

This image taken from reference [2] shows the shadow volume of a spherical

occluder.

Here’s how the depth pass method works:

1. Render the entire scene with only ambient and non-shadow casting lights enabled. 2. For each shadow casting light 3. Disable writing to the depth and color buffer. 4. Render the front face of all shadow volumes. If the depth test passes, increment the stencil buffer. 5. Render the back face of all shadow volumes. If the depth test passes, decrement the stencil buffer. 6. Enable writing to the depth and color buffer. 5. Render the scene with additive blending and only the shadow casting light enabled. Set the stencil test to pass only if the value in the stencil buffer is zero.

These images taken from reference [2 ] demonstrate counting shadow volume intersections.

Calculating the shadow volumes.

Several methods exist for calculating the geometry of a shadow volume. A shadow casting object must be a closed mesh. This means that there are no holes or gaps into the interior of the geometry. In a closed object, every edge is shared by exactly two faces. The silhouette of an object is the set of edges with one face pointed towards the light, and another pointed away. A shadow volume is created by extruding the silhouette of an object out to either a very large distance or to infinity.

Here is an algorithm to find an object’s silhouette:

1. Let S be a set of edges which is initially empty. 1. For each face F in the object 2. If F faces the light source 3. For each edge E in F 4.If E exists in S 5. Remove E from S 6.Else 6. Insert E into S

After this algorithm runs, S will contain every edge in the object’s silhouette. The Depth Fail Technique Depth pass works fine for many cases, but has problems when the camera enters a shadow volume. This is illustrated below:

The depth fail technique, also known as Carmack’s reverse, is the solution to this problem. Instead of using the stencil buffer to count how many shadow surfaces pass the depth test, it counts how many shadow volume surfaces fail the depth test. This is illustrated below:

This algorithm is only a sleight change to the depth pass algorithm:

1. Render the entire scene with only ambient and non-shadow casting lights enabled. 2. For each shadow casting light 3. Disable writing to the depth and color buffer. 4. Render the back face of all shadow volumes. If the depth test fails, increment the stencil buffer. 5. Render the front face of all shadow volumes. If the depth test fails, decrement the stencil buffer. 6. Enable writing to the depth and color buffer. 5. Render the scene with additive blending and only the shadow casting light enabled. Set the stencil test to pass only if the value in the stencil buffer is zero.

The only disadvantage to this method is that shadow volumes must now be capped. The figure below illustrates why:

Conclusions

Both shadow mapping and stencil shadowing have strengths and weaknesses. Stencil shadowing is the slower of the two techniques because it requires additional rendering steps as well as a great deal of calculation each frame to compute the shadow volumes. Much of this can be sped up greatly on modern graphics hardware though. Shadow mapping is relatively fast, but as stated before it has problems with aliasing when the shadow map resolution is low. It’s my opinion that stencil shadows are the best looking and should be used if one can afford them. But in a scene with very high polygon counts, the high cost of computing shadow volumes may force the programmer to use shadow mapping.

[1] Cass Everitt, Ashu Rege, Cem Cebenoyan. Hardware Shadow Mapping. http://developer.nvidia.com/object/hwshadowmap_paper.html

[2] Hun Yen Kwoon. The Theory of Stencil Shadow Volumes. http://www.gamedev.net/reference/articles/article1873.asp

[3] Marc Stamminger, George Drettakis. Perspective Shadow Maps. http://www-sop.inria.fr/reves/publications/data/2002/SD02/