© 2004 Ben
Woodhouse
This
interactive demo combines several lighting and shadowing techniques in order to
simulate realistic lighting for a game environment. Stencil shadows are used to
achieve real-time shadowing, and per-pixel lighting techniques are used to
render the different surfaces in a realistic way
Explore the
scene and reposition lights in order to see the effects of the dynamic lighting
system. Further options can be specified using the init.xml config file (see
below).
Recent
video card drivers are also fairly important.
Important:
Unless your video
card is very expensive, DISABLE ANTI-ALIASING in your drivers. Stencil
shadowing is fill-rate intensive.
Note: if
you have a non-SSE machine, such as an old Athlon (pre-XP), download the patch
from my web site.
There are
two camera modes in the demo. These can be toggled using the F1 key.
In the walk
mode, the camera acts like a camera in a first person shooter game. The player
can move around the scene, using the mouse to rotate and the cursor keys to
walk..
In the
orbital mode, the camera orbits the scene. The camera can be zoomed using the
mouse wheel, or A and Z on the keyboard. To rotate the camera, hold the right
mouse button and drag.
Light
tracking is enabled or disabled with the L key. Light tracking causes one of
the lights in the scene to track the camera position. Disabing light tracking
causes the light to remain where it was last placed. Using this method it is
possible to position the movable light anywhere in the scene.
The main
menu can be accessed by pressing escape. From here you can quit or change
various options.
Various
options can be configured in the init.XML file, which can be found in the
config files directory. Changing many of these options is inadvisable unless
you know how the engine works, but it’s relatively simple to add lights to the
scene.
For example, to add a blue light to
the scene, navigate to the scene element, and add the following code:
<light range="0" castShadows="1">
<position x="-2000" y="3000" z="-2185.04" w="1.0"/>
<diffuse r="0.1" g="0.1" b="0.6" a="1.0"/>
<specular r="0.3" g="0.3" b="0.6" a="1.0"/>
</light>
Note: Currently the range attribute
is unsupported, so leave this at 0.
The demo
uses a multi-pass algorithm, similar to Doom 3’s to render multiple lights. An
initial ambient pass writes the Z buffer values and fills the ambient colour.
Each light adds another pass.
Each
lighting pass performs diffuse and specular bump mapping. Gloss maps used to
vary shininess at each point. Unlike Doom 3, the shininess power coefficient
(and thus the highlight size) can be varied based on the gloss map texels,
which means more realistic surface refraction can be achieved (see John
Carmack’s speech to DoomCon, 2004).
The program
renders shadow volumes by calculating their bounds and determining if they fall
within the view frustum. The bounds are approximated using an 8-sided bounding
pyramid. The camera’s position relative to this bounds pyramid is used to
determine the most efficient way of rendering the shadows.
The demo
uses a depth-fail shadowing algorithm where the camera lies within the shadow’s
bounds pyramid. Elsewhere, a depth-pass method is used. Shadow volume caps are
only rendered if necessary.
A major
part of this program was the development of a C-like scripting language,
BunnyScript. Bunnyscript is used in order to provide per-object/mesh programmability equivalent to the per-vertex
functionality that vertex shaders provide. This avoids the need to hard-code
per-object functionality, saving on compile time and increasing shader
flexibility.
BunnyScript
is compiled to a form of bytecode, then interpreted using a virtual machine.
The VM has been optimised sufficiently to run several hundred object shaders per
frame with minimal overhead. BunnyScript is a flexible language, and can be
applied to more general scripting tasks in addition to object shaders.
Fully
animated models with transformation hierarchies are possible using the B3D file
format, which was developed as part of the framework for this program. In this
program, the scene is fairly static (with only one animated mesh), however,
character skinning is also supported and this is used in other programs.