Real-Time Radiosity
Real-time computer graphics generally uses only direct illumination, which is the simulation of light that is emitted from a light
source, bounces off one surface, and then hits the eye/camera. For realistic images, it is essential to simulate not only
direct illumination, but light that
bounces off two or more surfaces on the way to the camera. This is called global illumination.
In most real-time graphics, such as in computer games, the indirect illumination is approximated by a constant term, eg. the
ambient term in the Phong lighting equation[1][2]. The problem
with this is that it looks very flat.
Radiosity
Radiosity is a special case of the global illumination problem, in which all surfaces are perfectly diffuse reflectors (Lambertian).
This means stuff like specular reflection, glossy reflection, transmission etc.. doesn't have to be dealt with.
Real-time direct lighting on modern hardware
Real-time direct lighting, from a point light, with shadowing, on modern 3D-acceleration cards is very doable.
A commonly used algorithm is stencil shadow volumes[3].
A simple scene, lit with one point light, and rendered with shadows, can easily be rendered in less than 10ms (i.e. > 100 FPS)
on modern hardware. The lighting equation is either evaluated at vertices, and interpolated across triangles, or evaluated
for each fragment using fragment shaders.

The scene lit with only direct illumination. Staggered lights are used to achieve soft shadows
Real-time radiosity techniques
There seem to be several techniques for real-time radiosity on graphics hardware. The first is a gathering approach: Illumination
incident at a point is evaluated by rendering the scene from the point, usually rendering each hemicube surface into a pbuffer.
Weighted pixel colours are then summed to get the irradiance at that point, or spherical harmonic coefficients are computed from the
pbuffers, if directional radiance information is needed. Such a technique is described in [4].
Coombe et al. present a progressive refinement technique that uses hardware hemisphere rendering for form factor calculation in [5].
Another technique is
instant radiosity:
Instant radiosity
I had the idea of approximating light reflected off surfaces by a series of point lights. Turns out this had been done back in 97,
and was called 'instant radiosity'[6] :P
Read the instant radiosity paper for a good technical description of the algorithm. Basically, rays are traced out from the light
source into the scene. At the point where the rays hit a surface, a point light is added to approximate the reflected light from
that part of the scene. The ray keeps bouncing around the scene, being attenuated by the diffuse reflectivity of the surfaces it bounce off.
A Russian roulette scheme is used to terminate the ray after a finite number of bounces, while being un-biased. This is a Monte-Carlo technique
because it uses random new directions for the rays when they are reflected from a surface.
N rays are emitted from the light source, where N needs to be at least 100 to get a good image. Depending on the Russian roulette scheme used,
something like 2N light sources will be added at ray intersections. Finally, the scene is rendered,
using only direct illumination from the primary light source, plus
direct illumination from each of the ~2N 'secondary' light sources.
Tracing the rays should be a trivial part of the frame computation time. The bulk of the time is used to compute lighting from 200 or so point
light sources.

The scene lit with full direct + indirect illumination. Locations of secondary light sources are shown with yellow
spheres

The scene shown with only indirect illumination.

The scene shown with lighting from one of the many secondary lights. The intensity is exaggerated to show it clearly.
Note that because the reflecting surface is green, only green light is reflected

The scene lit with full direct + indirect illumination.
Shadows from secondary lights are enabled, leading to a low framerate.
Gamma correction
Gamma correction is performed so that the monitor intensity of each pixel is proportional to the intensity computed in the
scene. This is done by copying the framebuffer to a texture, then rendering the texture back to the framebuffer, raising each
colour component to power of 1/2.2 with a GLSL fragment shader program.
Precision issues
When adding the contribution from many lights together into one image, precision issues inevitably arise. I use the accumulation
buffer in OpenGL to store the intermediate image as light contributions are progressively added. Whereas the framebuffer on a
3d card usually has 8 bits per colour channel, the accumulation buffer has more precision, and allows floating point operations on it
to minimise precision loss. The downside of using the accumulation buffer is that using pixel buffers (PBuffers) as intermediate buffers
is more efficient, as they can be bound directly as textures, avoiding a copy operation from framebuffer to pbuffer when doing a final gamma
correction pass.
Care must also be taken when rendering the illumination from secondary lights. They are typically so dim, that massive rounding
errors occur due to limited framebuffer precision, unless the lights are given a intensity boost, and then a compensating attenuation
is made when copying to the accumulation buffer.
Gamma correction also accentuates limited precision for smaller colour values, contributing to banding artifacts in dark regions of the image.
Some of these issues could be avoided by using a fully floating point rendering pipeline, with floating point pbuffers. While
such a pipeline is possible today, it requires the use of fragment shaders to output the floating point colour values,
and it is in general a lot slower than using the fixed-function pipeline.
Optimisations/Hacks
One hack is to not use shadows when computing illumination from secondary light sources. This allows the frame to be drawn in
much less time, because for example 8 lights can be drawn in one pass. When shadows are used, the stencil volume shadow
algorithm requires at least one pass per light. Thus not drawing shadows from the secondary lights can result in 8 times less
passes, and a corresponding reduction in 'fill-rate' used. The downside to using this hack is that it results in an incorrect
image; in particular 'light leakage' occurs, which is when indirect light 'leaks past' an occluder to illuminate the far side of it.
To prevent surfaces on the back side of the light-reflecting surface from being illuminated when shadows are disabled, spotlights with
a cone angle of 90 degrees are
used, so that only surface points on the front side of the surface are illuminated.

(Exaggerated) illumination from one secondary light source, with shadows.

(Exaggerated) illumination from one secondary light source, with no shadows.
Intensity divergence
One of the issues that arises when approximating illumination from a surface with a series of point lights is that
very near the point light, as the intensity is proportional to the inverse square of the distance, the intensity goes
to infinity. This manifests itself as very bright spots in the image, always found at the concave edge shared between two
intersecting surfaces. This can be worked around by setting the constant coefficient in the OpenGL lighting equation to a non-zero
value, so that the illumination from a light never exceeds a certain threshold. The intensity then takes the form A/(B + r2)
instead of A/r2. This has the side effect of lowering the overall brightness of the scene, but it's worth it in the end :)
Performance
GeForce FX 5200 (really old and crappy card)
FPS for the Cornell box scene shown in the pictures above with about 200 secondary lights,
and without secondary shadows: ~5.3 FPS
with secondary shadows: ~1.1 FPS
GeForce 6800gt: (courtesy of Warpath)
FPS for the Cornell box scene shown in the pictures above with about 250 secondary lights,
and without secondary shadows: 60-100 FPS
with secondary shadows: ~17 FPS
DAMN that's a fast card :)
Demo
Requirements: Windows, newish drivers (needs GLSL support among other things), newish 3D card (approx GeForce FX 5200+, Radeon 9000 +).
rtrad.zip v1.0
More screens
Credits
Written by Nik Chapman a.k.a. Ono-Sendai, 2004.
Thanks to SnowKrash for comments and for finding the Instant Radiosity paper.
References
1: Illumination for computer-generated images, Communications of the ACM, Volume 18, Issue 6, June 1975
2: Phong For Dummies (Delphi3d.net)
3: Practical and Robust Stenciled Shadow Volumes for Hardware-Accelerated Rendering, Cass Everitt and Mark J. Kilgard March 12, 2002
4: Real-Time Global Illumination on GPU
5:
Radiosity on Graphics Hardware, Coombe et al.
6: Instant Radiosity, Computer Graphics Proceedings, Annual Conference Series, SIGGRAPH 97, pp. 49-56.
Back to Homepage.