September 9, 2012

Omnidirectional Shadow Maps

Requirements: Direct3D 11, Visual Studio 2012
Source code: Omnidirectional Shadow Maps



These days shadow mapping algorithm for constructing shadows on curved surfaces seems to dominate in game and film industries. The idea behind it is the following. It is assumed that you are located at the light source and render the scene from its position to a texture [1],[2]. All the points that could be seen from this position are lit and all the others are in shadow. To determine visible surfaces from the light source, you could render the scene to Z-buffer, which is called shadow (depth) map, discarding writing to color buffer. After, another render pass is executed from the viewer position. The position of each rasterized fragment is transformed to light clip space. Its z-coordinate defines its distance to the light. If it is greater than a corresponding one in the shadow map, then the fragment is shadowed otherwise it is not.

The described above technique will work alright for the case we have a spot light. Should we have a point (omni) light source which emits light in all directions, the approach above should be modified. This time we create 6 shadow maps with a separate view matrix having field of view 90 degrees along +x, -x, +y, -y, +z, -z coordinate axes so that to cover all the space around the light source. Cube texture could be the right choice for storing such kind of data.

In the vertex shader we calculate world space vertex position and world space direction from the light source to the vertex and pass them as attributes to the geometry shader. Using instancing mechanism of geometry shader we are able to render all the shadow maps in one pass [3]. The semantic SV_GSInstanceID provides the index of the shadow map we process and allows us to choose the proper light view projection matrix to calculate clip space position of the vertex and redirect the primitive to the proper face of cube texture via another semantic SV_RenderTargetArrayIndex. In the pixel shader we receive interpolated world space light direction, the length of which is written to the shadow map.

During the shading pass, we again use vertex shader to calculate world space light direction and pass it to the pixel shader. In the pixel shader, the interpolated light vector is used to sample the cube shadow map for the stored distance and its length as a comparison value.

Interaction:
Press "space" button to launch/stop torus animation.

References:
1. Tomas Akenine-Möller, Eric Haines, Nathaniel Hoffman. 2008. "Real-Time Rendering"
2. Elmar Eisemann, Michael Schwarz, Ulf Assarsson, Michael Wimmer. 2012. "Real-Time Shadows"
3. Jason Zink, Matt Pettineo, Jack Hoxley. 2011. "Practical Rendering and Computation with Direct3D 11"
4. Gerasimov Philipp, "Omnidirectional Shadow Mapping" in GPU Gems, Addison-Wesley, pp.193-2003, 2004.

No comments:

Post a Comment