i
i
i
i
i
i
i
i
9.1. Shadows 335
As expected, this matrix turns into the matrix in Equation 9.5 if the
plane is y = 0 (that is, n =(0 1 0)
T
and d =0).
To render the shadow, simply apply this matrix to the objects that
should cast shadows on the plane π, and render this projected object with
a dark color and no illumination. In practice, you have to take measures to
avoid allowing the projected polygons to be rendered beneath the surface
receiving them. One method is to add some bias to the plane we project
upon, so that the shadow polygons are always rendered in front of the
surface. Getting this bias just right is often tricky: too much, and the
shadows start to cover the objects and so break the illusion; too little,
and the ground plane pokes through the shadows, due to precision error.
Biasing solutions are discussed in Section 11.4.
A safer method is to draw the ground plane first, then draw the pro-
jected polygons with the Z-buffer off, then render the rest of the geometry
as usual. The projected polygons are then always drawn on top of the
ground plane, as no depth comparisons are made.
A flaw with projection shadows is that the projected shadows can
fall outside of our plane. To solve this problem, we can use a stencil
buffer. First, draw the receiver to the screen and to the stencil
buffer. Then, with the Z-buffer off, draw the projected polygons only
where the receiver was drawn, then render the rest of the scene
normally.
Projecting the polygons this way works if the shadows are opaque. For
semitransparent shadows, where the underlying surface color or texture can
be seen, more care is needed. A convex object’s shadow is guaranteed to
have exactly two (or, by culling backfaces, exactly one) projected polygons
covering each shadowed pixel on the plane. Objects with concavities do
not have this property, so simply rendering each projected polygon as semi-
transparent will give poor results. The stencil buffer can be used to ensure
that each pixel is covered at most once. Do this by incrementing the sten-
cil buffer’s count by each polygon drawn, allowing only the first projected
polygon covering each pixel to be rendered. Alternately, the ground plane
could be drawn, the Z-buffer cleared, and then each successive shadow
polygon is drawn increasingly offset (e.g., using glPolygonOffset)sothat
it is further away than the previous polygon. In this way, each shadowed
pixel is drawn only once [663]. This works, but the ground plane may need
to be redrawn into the Z-buffer (only) to reestablish the correct z-depths,
if needed.
One way to avoid the problems of rendering multiple projected shadow
polygons atop a ground plane is to instead render these polygons to a
texture. This texture is then applied to the ground plane. Essentially, this
texture is a form of a light map. As will be seen, this idea of rendering the
shadow projection to a texture also allows soft shadowing and shadows on