Rather than creating a correct soft-edged shadow from an area source,
the algorithm creates a shadow of a soft-edged object from
a point source
(Figure 1). The penumbra is the
shadow of the semi-opaque (outer) object that is not also shadowed by the
opaque (inner) object. The transparency of the outer object increases
from no transparency next to the inner object to
full transparency at the boundary of the outer object.
For an isolated object, we can use inner and outer
offsets of the real object to achieve believable results. We also
need to make the intensity gradient in the penumbra natural. This
can be achieved by computing a variable
that begins at
on the penumbra/umbra boundary (the surface of the inner object)
and increases linearly with distance
to
on the
outer boundary of the penumbra (the surface of the outer object).
This can control an interpolation
of the illumination attenuation function s. For diffuse spherical
lights and occluders with a straight edge, the
attenuation is a sinusoid:
.
To mimic this
behavior with a polynomial we use the
Bernstein interpolant:
,
which has the same values and
derivatives as the sinusoid at
and
.
![]() |
While almost any inner and outer surfaces are practical for an isolated
object, we would like our algorithm to remain simple and robust for
multiple objects. For example, if a point is in the penumbra region for two
objects we can make a composite attenuation factor based on the
individual factors s1 and s2. Obvious candidates are
addition:
s = 1 - ((1-s1) + (1-s2)), multiplication: s = s1 s2, and
thresholding:
.
All will yield continuous intensity transitions and visually
pleasing results for the shadow of two objects.
However, thresholding is more conservative when many
distinct objects are grazed by a shadow ray, resulting in shadows that
are never darker than they should be.
The remaining important issue is how the inner and outer objects are
generated for an input object. Figure 2 shows why the inner
object must be at least as big as the input object to prevent
``light leaks'': any gap between the inner objects would result in a
nonzero s and a lightening in the middle of the shadow.
For this reason we use the object itself as the inner object.
For the outer object, we use an image of the input object
that is expanded in a direction natural for the particular primitive.
For example, for a sphere, we use a larger sphere. For a polygon, we
use a larger polygon. Our rationale for choosing the size of
the outer object is shown in Figure 3.
We would like the penumbra width in the approximation to be approximately
W. Since
and
b / (A-a) = W/A, a reasonable penumbra
size will occur when b = aD/A. Note that the umbra region will be
larger than in a physically-based computation, but when the
occluder size is large relative to the light size, this should not be
too noticeable. An example of the mechanics of the algorithm is
discussed in the Appendix.
![]() |