2005 – Rabid

About
The Rabid engine computes global illumination using graphics hardware. Rabid uses a progressive radiosity solution in multiple passes using render to texture and fragment shaders to accumulate light. The techniques used in Rabid were inspired by (but not copied from) Brian Ramage’s article “Fast Radiosity: Using Pixel Shaders” featured in the August 2004 issue of Game Developer Magazine.

Overview
Rabid uses a simple and straightforward algorithm to distribute light throughout a scene. Each surface has an associated lightmap, accumulation, and residual texture. The accumulation texture gathers light for the surface. When lighting is complete the accumulation texture is copied to the lightmap texture which is then displayed. The residual buffer also gathers light for a surface, and represents the light being reflected off the surface. Residual light is used to determine the brightest surface and create lights. When lights are created for a surface it’s residual texture is cleared (that energy has left the surface and been distributed as lights). Rabid allows the user to see residual light by pressing tab.The main algorithm used to distribute light throughout the environment is as follows:

for each surface clear accum    for each step     choose surface with most residual light    create lights from surface    clear residual light from brightest surface        for each surface      for each light         frame surface from the light         render the surface with the light         render all other surfaces black (occluders)         add light to accumulation buffer         add light to residual buffer copy accumulation buffer to lightmap texture

Framing
A surface is framed from a point by aligning the view matrix with the tangent space of the surface looking down the negative normal of the surface. The projection matrix is then chosen such that the frustum fits the extents of the surface. This is almost always an asymetrical frustum, unless the light is directly above the surface. Framing the surface in this way allows for trivial shadows. Rendering all other surfaces black projects the shadow onto the surface being lit.

Precision
Standard 8-bit per channel precision is unable to account for the minute amount of light that is being distributed during a radiosity step. 32-bit per channel floating point textures would be ideal, however OpenGL does not support convenient rendering to float textures (it involves using p-buffers which are extremely cumbersome). To save time I chose to pack a 32-bit float into the four 8-bit color channels of a standard texture using a pixel shader. Rabid deals with residual and accumulated light in high-precision packed textures, and after the light has accumulated it is copied to a standard 8-bit color texture. This allowed one high precision channel storing intensity, but no color. The first three screenshots show the problem of precision. Note that this scene is only light by one light. The third screenshot shows high precision lighting, and the fourth shows the packed 32-bit float stored in the 8-bit color channels.

Results
Rabid can light one surface from an area light source in less than a second, and can complete one radiosity step on a simple map (16 surfaces) in about 2-3 seconds. This could be optimized, but Rabid was designed to show the user each surface as it was being lit, a process which takes an few extra render to textures. There is no real limit to the complexity of the maps.A maya exporter was developed near the end of this project, but it wasn’t fully finished. Some of the maya exported maps produced odd tangent spaces which in turn resulted in incorrect lighting. Some maya maps worked, some did not. There wasn’t enough time to find the cause.

Enhancements
Future enhancements to Rabid:

  • Preview mode
  • Represent each area light by one directional light at the center allowing for extremely fast lighting calculations that can be previewed in near realtime.

  • Uniform Texture Space
  • The texture space in Rabide are (0,1) over all surfaces. This means that larger surfaces have larger texels than smaller surfaces, which could mean a loss of detail. Allowing texture space to relate to real space would give a more uniform texel distribution.

  • Full Precision
  • Though packing handles precision decently, there are still artifacts of the packing and unpacking. Full 32-bit per channel float textures would allow for even more precision and also colored lights.

Screenshots
The radiosity steps all use 16×16 accumulation, residual, and lightmap textures.

hwrad1.jpg hwrad2.jpg hwrad3.jpg
hwrad4.jpg hwrad5.jpg hwrad6.jpg
hwrad7.jpg hwrad8.jpg hwrad9.jpg
step0.jpg step1.jpg step2.jpg
step3.jpg steps.jpg

Leave a Reply