© 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 processor, 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.