|
Creating
Effects
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:
- Draw
Shadows: Allows you to turn on and off shadow rendering.
- Show
Shadow Volumes: Draws the shadow volumes used to compute the shadows
rather than drawing the shadows themselves.
- Draw
Shadow Volume Caps: When you turn this item off, some "extra"
shadows might become visible where the far caps of the cylindrical
shadow volumes happen to be visible.
- 1-Bit
Stencil Buffer Mode: Tells the code to use a different algorithm
that uses only 1 bit of stencil buffer, which won't allow overlapping
shadows. If the device supports only 1-bit stencils, you'll be forced
to use this mode.
- Z-Order
Shadow Vols in 1-Bit Stencil Buffer Mode: The shadow volumes must
be rendered front to back, which means that if you don't check this
option, rendering might be incorrect.
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.
|
<<"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.
|