| |
|
|
||||
![]() |
||||||
| |
|
|||||
|
Implementation: Birth of a Shadow Volume The first step in creating a shadow volume is to develop an effective method for identifying the shadowing edges of any object. Among the many available techniques for determining the edges, we discovered that the quickest method entails generating face connectivity information before runtime. Connectivity data is stored as an internal list of all neighboring faces for every triangle. Listing 1 shows pseudo-code that suggests how to generate the connectivity. This can be accomplished either during the loading of the model, or the data can be preprocessed and stored into the file format. Once this information is available, an application can efficiently determine boundary edges of an object. Edges are determined by culling faces that are not viewable from the current light perspective, and then identifying edges that lie along the boundary of the culled and not-culled faces. Listing 2 shows the pseudo-code that represents this routine. Source code for all methods described in this article can be found in the demo project, which is downloadable from the Game Developer website.
After the boundary edges have been detected, polygons can be generated to form the actual shadow volume. This can be accomplished simply, or it can be a more difficult task, depending on the approach. At the most basic level, two new vertices need to be created in the direction of the light, away from the vertices of the current edge. With the resulting four points, two simple triangles can be formed. A number of complexities arise depending on how far you want to extend the new points. Three possible implementations are as follows:
Implementation: The Baby Grows Up Once the shadow volume has been generated and stored in memory, the real fun begins. As mentioned in the overview, the volume must be rendered in its entirety to the stencil buffer only; no color information should be displayed. Listing 3 shows the Direct3D implementation of the appropriate renderstate settings. The polygons are rendered in flat shading mode, as we do not want the card to waste cycles on gouraud shading that will never be displayed. The stencil buffer values are incremented for every pixel that the card renders during this pass.
Just when you thought your volume rendering days were over, we must make another render pass using the same polygons. This time we must really shake up the natural order of the universe and reverse the cull mode, as well. Listing 3 shows the Direct3D implementation for setting the appropriate second-pass rendering. Note the changes in the stencil functionality, as well as the cull mode reversal. The volume is then rendered to the stencil buffer in the same style as the first pass, but this time decrementing the stencil values rather than incrementing them. Remember to set the Z-buffer, stencil buffer, and cullmode back to their proper settings before proceeding to render the next scene. The application must repeat the volume generation and rendering for every shadowed object, for the current light, before rendering the actual shadow. This not only increases performance (since rendering the true shadows can be costly, as we will soon find out), but this method avoids creating multi-darkened artifacts in the shadows. At this point, the visual representation of the shadow can be rendered. The principle is very simple. Two large, gray, alpha-blended triangles are rendered to the entire screen. The stencil operations are set to only render pixels that have a corresponding positive value in the stencil buffer. Listing 4 shows the renderstates used to accomplish this operation.
The
Darkness and the Light: Pros and Cons Greatly improved realism is the most significant gain offered by real-time shadow casting. When you use full shadow casting, an entire scene behaves realistically with any number of polygons and objects. Scenes can be completely dynamic, with no previous lighting calculations necessary (excluding the connectivity information mentioned earlier). Objects will also shadow themselves, something that is not easily done with texture-mapping techniques, due to the intensive computations and the number of texture passes that are necessary. Reducing the number of texture passes required for a scene is another large benefit of the shadow casting method. With texture-based shadows, as described in earlier articles in this publication, the number of texture modifications and renders needed to shadow a well-populated scene becomes excessive and unbearably complex. Hardware graphics accelerators are unpredictable in their texture-rendering performance across different chipsets. The shadow-casting method is more fill limited, a metric that is more easily understood when coding for the widest range of accelerators. For all its benefits, shadow casting also has a dark side (this time, the pun was initially unintentional), as many new technologies do. The foremost problem is the reliance upon 8-bit stencil support on the graphics hardware. This factor was especially significant at the time the sample code was originally written. Looking towards the future, however, we predict that 8-bit stencil support will become standard within the next hardware generation. Card fill rate also ranks as an important concern, as the number of polygons that must be manipulated rises dramatically with shadow casting. Shadow rendering can easily become the application bottleneck. The only upside to this is that more CPU cycles can be spent in other application areas without affecting frame rate beyond the shadow bottleneck. A smaller concern is the generation of 'sharp' shadows as a by-product of the technique itself. Since shadows are generated by polygonal edges, they are perfectly crisp on their boundary. In many situations, 'soft' shadows that either attenuate or dither at the edges provide a more pleasing complement to the lighting in a scene. Since the actual polygon rendering is performed blindly across the entire screen, these kinds of softening operations are extremely difficult to perform and slow down processing considerably (to the point of being impractical to implement). Also, if an object is either extremely detailed or very small on the screen, the shadow cone polygons can become single pixel width or smaller. This causes visual anomalies onscreen in the form of gaps or shadow flickering. The last potential problem with shadow casting involves the complexities of advanced scene management, particularly in cases where more than simple overhead lights are used (note that most shadow casting demos only show the simple case). The next section addresses this issue and other problems in more detail, with some suggestions on how to alleviate potential issues. |
|
|