Radiosity Using Photon
Maps
James L. Bigler -
Peter Shirley -
Steven G. Parker
Abstract
The effect of global illumination is necessary for realistic images. In this paper we explain a method of generating photon maps that can later be used to texture surfaces. These texture maps are generated by tracing the light emitted from light sources and recording where the light is absorbed. This enables the textures to have all the illumination properties of shadows and global lighting encoded in them.
Background
We will assume the reader has a basic knowledge of how to implement a simple ray tracer with parallelogram primitives. We also assume an understanding of what global illumination is as well as how to implement texture mapping to view the results.
Global illumination is achieved by tracing the path of rays emitted by the light source and keeping track of where the light went. As light strikes a surface, energy from the light is absorbed. If the surface is broken into smaller regions we can keep track of how much light hits each region. These regions correspond to the texels of the photon map.
As a post process operation, we normalize the amount of light in each texel by the area. We also normalize by the scene's maximum light value to give the brightest texel the value of 1 or the brightest color representation. The texels are then written out to image files to be used as texture maps in a rendering system.
Implementation
The implementation can be thought of in three main parts:
Tracing the light emitted from the light source
From the light source you can generate a light ray that has both
direction and color. You may keep track of the color as a RGB unit or
trace each color independently. Using the ray from the light you
compute the intersection in your scene. Once computed, you contribute
light to the corresponding texel of the surface. Since the objects in
the scene absorb light we need to determine when the light should no
longer contribute. We compute the probability of terminating the ray,
by using the components of the light color, probability = (red + green
+ blue)/3. We then take a random number (r) from [0..1] and if the
probability is less than r we terminate the ray. One could also
compute probability by using probability = max (red, green, blue).
If the ray is not terminated, the ray continues and two things must be calculated, the new direction and color. The direction is computed using the normal of the surface and a random direction in the hemisphere made by that normal. The color is computed using the product of the surfaces' color with the light's scaled by the dot product of the incoming ray with the intersecting polygon (New_Color = RGB(light.r * surface.r, light.g * surface.g, light.b * surface.b) *-light.direction . normal).
This process is repeated until the light is terminated. When the light is terminated another ray from the light source is generated.
Keeping track of how much light hit each surface
The light is kept track of using a two-dimensional array corresponding
to the u-v parameterization of the surface. Any surface may be used
provided a u-v parameterization exists and the area per texel is
known.
All surfaces in the scene are apportioned a 2D texel map initialized to 0. When an intersection is obtained the corresponding texel's value must be incremented by the per color product of the lights color with that of the surface's.
Generation of the texture maps to be used in a rendering system
Once a predetermined number of rays from the light sources have been
traced, the process of texture creation can commence. Because the
maximum value of a texel can depend on the number of light rays traced
in a scene, the values of the texels must be normalized by the maximum
of each color. Looping over the set of texels in the scene the maximum
values for each color component is determined. A second pass is done
to normalize each color value with its corresponding maximum. During
this process the value of the texel is also divided by its area.
The texture maps can then be saved or used appropriate for the rendering system. We chose to use the real time ray tracer developed by Steve Parker and Pete Shirley, because of the capabilities of using large amounts of texture memory. The files were saved on a per polygon basis and read in on visualization start up.
Results
Only rectangular primitives were used in the creation of our scenes. As stated earlier other primitives with adequate u-v parameterizations and known texel areas such as triangular meshes or NURBS could be used.
As this is a scene that depends on even distribution of random rays, quality of the textures increases with the number of rays per texel. This helps reduce the speckling seen below. For decent results 100 to 1000 rays per texel is recommended.
| 10 rays per texel | 100 rays per texel |
![]() |
![]() |
| 1000 rays per texel | |
![]() |
Even though this is an "offline" preprocess it can be quite time consuming to generate these texture maps. Using a naive implementation on an Origin 3000 it took 240 processing hours to trace 100 billion rays with a scene that had 2.2 million texels. Some sample images are below.
![]() |
![]() |
More images for caparison can be found here.
Conclusions
This is straightforward implementation for global illumination. Unlike computing the form-factor which scales O(n^2) based on the number of discrete surfaces, this approach scales by the cost of computing intersections with the primitives. By using ray tracing optimizations such as a bounding hierarchy, the scaling can be O(n log n).
One of the drawbacks to this implementation is the cost of texture memory. With relatively complex scenes the use of OpenGL texture memory becomes impossible as the amount of texture required surpasses that in memory. For this reason we chose to use the real time ray tracer, because texture memory was only limited by main memory.