Shadows Computer Graphics
Shadows
Shadows Extended light sources produce penumbras In real-time, we only use point light sources –Extended light sources can be simulated using multiple point light sources Due to inter-object reflection, even point light sources can form penumbras
Shadows Most real-time shadow algorithms produce “hard shadows” rather than “soft shadows” –Hard shadows contain no penumbra –Soft shadows contain a penumbra Additionally, most real-time shadow algorithms only produce geometric shadows –Only the shape of the shadow is computed, but not its internal intensity
Shadow Algorithms There are many different real-time shadow algorithms (no clear winner yet) –Projected shadows –Shadow Z-buffer –Shadow volumes
Projected Shadows Project the vertices of the occluder onto the ground/wall plane based on the location of the light source Convex hull of projected vertices form the shadow polygon The shadow polygon can then be rendered in “shadow” color
Projected Shadows Main drawback of projected shadows is that they only project properly onto flat surfaces
Shadow Z-Buffer Shadow computation is integrated into Z- buffer computation Additional buffer (called a Shadow Z- buffer) is needed Forming the shadow is a 2 step process: –Computation of depth information –Render scene with modified Z-buffer algorithm
Shadow Z-Buffer To compute the depth information: –The scene is “rendered” from the point of view of the light –No intensities (colors) are stored in the framebuffer –Depth information is stored in the Shadow Z-buffer Thus, the Shadow Z-buffer contains pixel-based information on the depth of objects from the light –In particular, it contains the distance from the light source to the surface nearest the light source
Shadow Z-Buffer Next render the scene the normal way from the point of view of the camera, using a modified z- buffer test: –If point is visible (i.e. passes normal z-buffer test), a coordinate transform is used to map the point into the coordinate system of the light –The (x, y) parts of the transformed point are used to lookup the value in the Shadow Z-buffer –If the transformed z value is greater than the value stored in the Shadow Z-buffer then the point is in shadow and is rendered using a “shadow” intensity
Shadow Z-Buffer Note that one needs a separate Shadow z-buffer for each light source in the scene
Shadow Volumes A volume is swept out in space by the shadow of the occluder
Shadow Volumes Of course, the shadow volume is not actually rendered, but is used to determine the shadowed areas on the receiver
Shadow Volume To compute the shadow volume one must first find the silhouette edge of the occluder –The silhouette edge is made up of edges of the object that separate faces that are lit from faces that are facing away from the light source Rays are cast from the light source through the silhouette edges to form the shadow volume
Shadow Volume Any polygons that lie inside the shadow volume are in shadow
Shadow Volume Implementation The first step was to find the silhouette edge –Preprocess the object so that for each polygon you have a list of all connecting faces –Perform the back-face culling test on the faces in the object from the point of view of the light –Include any edge between a culled face and a non-culled face as a silhouette edge
Shadow Volume Implementation Next form the shadow volume from the silhouette edge –Form long quads with the edge vertices as 2 points and the other 2 points determined by the rays from the light through the edge vertices
Shadow Volume Implementation Piercing is a potential issue to think about when creating the shadow volume –Does the occluder cast shadows through walls The Shadow Volume is then to create a shadow using a multi-pass rendering of the scene using the stencil buffer
Stencil Buffer A Stencil Buffer is another buffer like the color (frame) buffer and the Z-buffer –On most hardware this is an 8 bit buffer The Stencil Test is a test that occurs immediately before the Z-buffer test –If the Stencil Test fails, the fragment is discarded rather than passed on to the Z-buffer Fragment won’t show up in the color buffer either
Stencil Buffer The Stencil Test is a test of the value currently stored in the Stencil Buffer The Stencil Function controls the type of Stencil Test to perform: GL_NEVERGL_ALWAYS GL_LESSGL_LEQUAL GL_EQUALGL_NOTEQUAL GL_GREATERGL_GEQUAL
Stencil Buffer There are 3 possible outcomes of the combined Stencil and Z-buffer tests: –Stencil Test fails –Stencil Test passes, Depth Test fails –Stencil Test passes, Depth Test passes The Stencil Operation lets you specify what happens to the Stencil Buffer values in each of these cases
Stencil Buffer The possible Stencil Operations are: –GL_KEEP old value kept –GL_ZERO value replaced by zero –GL_REPLACE value replaced by given reference value (allows setting to a specific value) –GL_INCR value incremented by 1 –GL_DECR value decremented by 1 –GL_INVERT value bitwise inverted
Stencil Buffer The Stencil buffer/test are only performed if –The Stencil buffer is enabled –The underlying hardware/drivers support it The stencil buffer is usually used as a mask –Example: creating a non-rectangular windshield for a first-person driving game Store 1s in the stencil buffer pixels where you wish the windshield to be and then set the stencil test to render if not equal to 0
Shadow Volume Implementation Here is a version of the multi-pass algorithm for shadow volume rendering: –Render the scene as if it was entirely in shadow (ambient light only) –Render front-facing shadow volume polygons to determine if any object polygons are behind them –Render back-facing shadow volume polygons to determine if any objects from the second pass are in front of them –Render the entire scene again, overwriting the results of the first pass with polygons that are not in shadow
Shadow Volume Implementation A slightly modified version of the multi- pass algorithm: –Render the full scene normally (full lighting) –Render front-facing shadow volume polygons to determine if any object polygons are behind them –Render back-facing shadow volume polygons to determine if any objects from the second pass are in front of them –Render the scene again, with only ambient light, overwriting the results of the first pass with polygons that are in shadow
Shadow Volume Implementation So where does the stencil buffer come in? –The stencil buffer will be used as a mask for our last rendering (either masking off all polygons that are in shadow or not in shadow – depending on the version of the algorithm) –The two shadow volume passes are used to create the mask in the stencil buffer
Shadow Volume Implementation To calculate the stencil buffer values: –Disable the frame buffer and z-buffer writing, leaving depth testing enabled –Initialize the stencil buffer to 0 –Set the stencil function to “always pass” This turns off masking ability of stencil buffer –Set the stencil operation to “increment if depth test passes” Will increase the value in the stencil buffer if the newly rendered polygon has a depth closer than anything previously rendered
Shadow Volume Implementation –Enable back-face culling Only front-facing polygons will be rendered –Render the shadow volume Given the previous setup: –No color values are changed in the frame buffer –No z-values are changed in the z-buffer –Only front-facing shadow polygons are processed –The stencil buffer is incremented for each pixel where there is an object polygon behind the front-facing shadow polygon
Shadow Volume Implementation –Set the stencil operator to “decrement if depth test passes” Will decrease the value in the stencil buffer if the newly rendered polygon has a depth closer than anything previously rendered –Enable front-face culling instead of back-face Only back-facing polygons will be rendered –Render the shadow volume Given the previous setup: –No color values are changed in the frame buffer –No z-values are changed in the z-buffer –Only back-facing shadow polygons are processed –The stencil buffer is decremented for each pixel where there is an object polygon behind the front-facing shadow polygon
Shadow Volume Implementation The end result of this is a stencil buffer that has a positive value if the pixel at that location is in shadow –Incremented because front-shadow in front of object polygon –Not decremented because back-shadow is not in front of object polygon This stencil buffer can then be used as a mask by setting the stencil function to “equality with zero” or “greater that zero” depending on if you want to mask object polygons that are in shadow or not in shadow
Planar Reflection Environment maps reflect a static texture mapped world onto a dynamic object –Key is texture projection functions based on reflection vectors Planar reflections reflect a dynamic world onto a static plane –Key is multipass rendering with a stenciling technique
Planar Reflection
The basic concept is to draw the objects you want reflected twice: –First in their reflected position –Then in their normal position In between these renderings the reflective planar surface needs to be drawn as a semi- transparent object whose color is blended with the color of the reflected object
Planar Reflection
If the viewer can see under the reflective plane then the illusion is lost We can maintain the illusion even in these circumstances by using the stencil buffer
Planar Reflection Note that what we want is for the reflected scene to only show up in the area of the reflective surface –i.e. mask the rendering of the reflected scene The mask is, of course, the stencil buffer We setup the stencil buffer by rendering just the reflective surface
Planar Reflection So the steps involved are: –Render the reflective surface to setup the stencil buffer as a mask Frame buffer should be turned off during this step –Render the reflected scene Scaling can be used to perform the reflection The stencil buffer should be used as a mask –Render the reflective surface again Semi-transparent and blended into the background –Render the scene again (not reflected this time)