Contents |
|
Creating
Effects
Figure 12-1,
Figure 12-2, and Figure 12-3 show three views of the scene generated by
the ShadowVol2 sample application. You can see the shadows in Figures 12-1
and 12-3; Figure 12-2 illustrates the shadow volumes.
Now that you've seen how to create stencil buffers and
configure how they work, let's look at some of the effects you can render
with them. The following sections describe several ways Microsoft
recommends using stencil buffers. Each of these approaches produces
impressive results, but a few of them have
drawbacks.
Composites
You can use stencil
buffers for compositing 2D or 3D images onto a 3D scene. By using a mask
in the stencil buffer to occlude a portion of the render-target surface,
you can write stored 2D information (such as text or bitmaps). You can
also render 3D primitives -- or for that matter a complete scene -- to the
area of the render-target surface that you specify in a stencil
mask.
Developers often use this effect to composite several scenes
in simulations and games. Many driving games feature a rear view mirror
that displays the scene behind the driver. You can composite this second
3D scene with the driver's view forward by using a stencil to block the
portion to which you want the mirror image rendered. You can also use
composites to create 2D "cockpits" for vehicle simulations by combining a
2D, bitmapped image of the cockpit with the final, rendered 3D
scene.
Decals
You can use decals to control
which pixels form a primitive image you draw to a render-target surface.
When you apply a texture to an object (for example, applying scratch marks
to a floor), you need the texture (the scratch marks) to appear
immediately on top of the object (the floor). Because the z values of the
scratch marks and the floor are equal, the depth buffer might not yield
consistent results, meaning that some pixels in the back primitive might
be rendered on top of those in the front primitive. This overlap, which is
commonly known as z-fighting or flimmering, can cause the final image to
shimmer as you animate from one frame to the next.
You can prevent
flimmering by using a stencil to mask the section of the back primitive on
which you want the decal to appear. You can then turn off z-buffering and
render the image of the front primitive into the masked area of the
render-target surface.
Dissolves
You can use
dissolves to gradually replace an image by displaying a series of frames
that transition from one image to another. In Chapter 8, you saw how to
use multiple-texture blending to create this effect by gradually blending
two textures together. Stencil buffers allow you to produce similar
dissolves, except that a stencil-based dissolve looks more pixelated than
a multiple-texture blending one. However, stencil buffers let you use
texture-blending capabilities for other effects while performing a
dissolve. This capability enables you to efficiently produce more complex
effects than you could by using texture blending alone.
A stencil
buffer can perform a dissolve by controlling which pixels you draw from
two different images to the render-target surface. You can perform a
dissolve by defining a base stencil mask for the first frame and altering
it incrementally or by defining a series of stencil masks and copying them
into the stencil buffer on successive frames.
To start a dissolve,
set the stencil function and stencil mask so that most of the pixels from
the starting image pass the stencil test and most of the ending image's
pixels fail. For each subsequent frame, update the stencil mask to allow
fewer pixels in the starting image to pass the test and more pixels in the
ending image to pass. By controlling the stencil mask, you can create a
variety of dissolve effects.
Although this approach can produce
some fantastic effects, it can be a bit slow on some systems. You should
test the performance on your target systems to verify that this approach
works efficiently for your
application.
Fades
You can fade in or out
using a form of dissolving. To perform this effect, use any dissolve
pattern you want. To fade in, use a stencil buffer to dissolve from a
black or white image to a rendered 3D scene. To fade out, start with a
rendered 3D scene and dissolve to black or white. As with dissolves, you
should check the performance of fades on the target systems to verify that
their speed and appearance is
acceptable.
Outlines
You can apply a stencil
mask to a primitive that's the same shape but slightly smaller than the
primitive. The resulting image will contain only the primitive's outline.
You can then fill this stencil-masked area of the primitive with a color
or set of colors to produce an outline around the
image.
Silhouettes
When you set the stencil
mask to the same size and shape as the primitive you're rendering,
Direct3D produces a final image containing a "black hole" where the
primitive should be. By coloring this hole, you can produce a silhouette
of the primitive.
Swipes
A swipe makes an
image appear as though it's sliding into the scene over another image. You
can use stencil masks to disable the writing of pixels from the starting
image and enable the writing of pixels from the ending image. To perform a
swipe, you can define a series of stencil masks that Direct3D will load
into the stencil buffer in a succession of frames, or you can change the
starting stencil mask for a series of successive frames. Both methods
cause the final image to look as though it's gradually sliding on top of
the starting image from right to left, left to right, top to bottom, and
so on.
To handle a swipe, remember to read the pixels from the
ending image in the reverse order in which you're performing the swipe.
For example, if you're performing a swipe from left to right, you need to
read pixels from the ending image from right to left. As with dissolves,
this effect can render somewhat slowly. Therefore, you should test its
performance on your target
systems.
Shadows
Shadow volumes, which allow
an arbitrarily shaped object to cast a shadow onto another arbitrarily
shaped object, can produce some incredibly realistic effects. To create
shadows with stencil buffers, take an object you want to cast a shadow.
Using this object and the light source, build a set of polygonal faces (a
shadow volume) to represent the shadow.
You can compute the shadow
volume by projecting the vertices of the shadow-casting object onto a
plane that's perpendicular to the direction of light from the light
source, finding the 2D convex hull of the projected vertices (that is, a
polygon that "wraps around" all the projected vertices), and extruding the
2D convex hull in the light direction to form the 3D shadow volume. The
shadow volume must extend far enough so that it covers any objects that
will be shadowed. To simplify computation, you might want the shadow
caster to be a convex object.
To render a shadow, you must first
render the geometry and then render the shadow volume without writing to
the depth buffer or the color buffer. Use alpha blending to avoid having
to write to the color buffer. Each place that the shadow volume appears
will be marked in the stencil buffer. You can then reverse the cull and
render the backfaces of the shadow volume, unmarking all the pixels that
are covered in the stencil buffer. All these pixels will have passed the
z-test, so they'll be visible behind the shadow volume. Therefore, they
won't be in shadow. The pixels that are still marked are the ones lying
inside the front and back boundaries of the shadow volume-these pixels
will be in shadow. You can blend these pixels with a large black rectangle
that covers the viewport to generate the shadow.
The ShadowVol
and ShadowVol2 Demos
The ShadowVol sample on the companion CD
in the \mssdk\Samples\Multimedia\D3dim\Src\ShadowVol directory contains a
project that shows how to create and use stencil buffers to implement
shadow volumes. The code illustrates how to use shadow volumes to cast the
shadow of an arbitrarily shaped object onto another arbitrarily shaped
object. The ShadowVol2 sample, which the Microsoft DirectX 7 SDK setup
program on the companion CD installs in the
\mssdk\Samples\Multimedia\D3dim\Src\ShadowVol2 directory on your hard
disk, provides some additional capabilities for producing shadows with
stencils.
The sample application provides these features in its
Shadow Modes menu:
<<"F12xi01.eps">>
|
Figure 12-1. Shadow
cast |
<<"F12xi02.eps">> |
Figure 12-2. Shadow
volumes |
<<"F12xi03.eps">> |
Figure 12-3. Another view of the rendered
shadows |
The Code
So Far
In this chapter, we didn't add any new code to the
RoadRage project. To see these effects in action, refer to the ShadowVol
and ShadowVol2 demo projects included in the DirectX
samples.
Conclusion
In this chapter, you learned
about stencil buffers and the exciting effects they can produce. In
today's market, making your code stand out is a requisite if you want it
to sell your applications and keep your users coming back for more.
Incorporating strategic stencil-buffer effects into the introduction and
into the body of a 3D real-time game might help you win over even the most
discriminating game players.
In Chapter
13, we'll discuss how to load and animate 3D models. Creating animated,
lifelike characters that your users can interact with is one of the most
powerful capabilities you can add to any game.
Peter Kovach has
been involved in computer software and hardware development since the
mid-1970s. After 11 years in various levels of development and project
management, he was eager to being pushing the envelope in 3D virtual world
development. He currently words at Medtronic, where he is the project lead
developming programmable, implantable medical devices that use a
next-generation graphical user interface.
Discuss this article in Gamasutra's discussion forums