I've now updated the real-time shadow code on this page to use
multiple processors if available to do the silhouette generation. This
code works quite well on SGI's Onyx and Onyx2 systems, increasing the
rendering speed. -mjk (6/30/97)
I think of OpenGL
as a vocabulary of hardware-amenable building blocks for 3D graphics
algorithms. By combining the "words" in this vocabulary in
clever, often unexpected ways, you can implement all sorts of real-time
graphics effects that would be difficult or impossible with an
uninspired API such as Microsoft's Direct3D. Is it possible that the
vocubulary provided by OpenGL is rich enough that it can generate
high-quality shadows in real-time? You bet it can.
The source code and screen snapshots below demonstrate real-time
shadows cast by object of arbitary shape onto arbitary geometry. The
shadows are not the simple "planar
shadow projections" so common in games and 3D graphics demos
today. These shadows can be cast onto curved surfaces and can even be
cast by objects with holes in them. The programs shown run at more than
15 frames per second on my SGI workstation. It could go faster with
further tuning.
The technique uses stencil-based shadow volumes to determine where the
shadow falls. OpenGL's feedback mode is used to capture the triangles
from an arbitary OpenGL-rendered object so that the object's silhouette
can be calculated with the OpenGL
Utility (GLU) 1.2 library's boundary tessellation routines.
I've implemented the shadowing algorithm as a library layered on top of
OpenGL so that OpenGL programmers just need to know where to position
casting light sources and shadowing objects with their 3D scene and the
library takes care of the details of generating correct shadows. The
library is the Real-Time Shadow (RTS) library.
Here are some screen snapshots to see how nicely the technique works:
Pretty cool, huh? Yes, this example runs in real-time on SGI machines
with the torus and cube contiously spinning while the user can
interactively adjust the lighting.
The last image is particularly interesting. Notice on the floor that
the shadow from the cube caused by the greenish light has a redish tint
since that area is also directly illuminated by the redish light. More
importantly, where this shadow overlaps with the redish's light's
shadow from the torus, you can see the shadow region is dark (neither
redish or greenish) as you would expect since the region is double
shadowed. This region is not directly illuminated by either light.
Still more interesting, you can see that on the cube, there is a shadow
from the torus blocking the red light. The shadowing objects can be
shadowed by other shadowing objects!
And also, don't miss how the smaller sphere has a shadow cast on it
from the torus and the greenish light. All these effects have been
captured in a single scene. Pretty nice.
The Real-Time Shadows library is implemented in rts.c
and its interface is defined by rtshadow.h
I'll mention that this library is still "under development",
but it is functional enough right now to do some really cool stuff. The
actual demo program is hello2rts.c.
I don't have time here to go into all the gory details of how the
algorithm works. It uses OpenGL's stenciling
capability (a rendering capability totally unsupported by
Direct3D). The flow chart below shows a simplified view of the key
points in the algorithm (for one object with one light source as in shadowfun.c).
Look up "shadow volumes" in a good graphics textbook for more
understanding of what's going on. The key observation is that after you
draw the front facing polygons of the shadow volume and then the back
facing polygons of the shadow volume (without color buffer or depth
buffer update, but with depth testing), shadowed pixels will be tagged
in the stencil buffer.
In the future, I'll be making further performance enhancements and
generalizations to the RTS library and supplying proper documentation
for it. Actually, if you look in hello2rts.c, you'll only find
10 different RTS calls.
I hope that you find this technique interesting. Like any rich,
powerful language, when you combine the vocabulary provided by OpenGL
in the right way, you can get OpenGL to render amazing scenes very
quickly.
If you are interested in more OpenGL rendering techniques, see the Way cool, way fast OpenGL
rendering techniques page.
The older version of rts.c before the
multiprocessor support.
- OpenGL Website