Raytracing / Photon mapping
This project demonstrates the applications of recursive ray tracing, enabling a high degree of visual realism due to the ability to better simulate global illumination models.
This project implements local diffuse and specular terms for each light (attenuated by the distance) before computing reflected and transmitted rays and their respective intensities using the Fresnel equations. These reflected and transmitted rays are then used as arguments in recursive calls to ray cast, and the colors produced are also attenuated.
These screenshots were rendered with a recursion depth of 12 and anti-aliasing. They also show shadows of transparent objects. Of course only the color of the shadow of a transparent object is implemented, the distortion of the shadow rays cannot be implemented in a straightforward fashion using backwards raytracing.
These screenshots were rendered with a recursion depth of 12 and no anti-aliasing.
When light reaches a surface, it will bounce or get transmitted in a way that is dependent on the surface: given an incoming light direction and wave length, it is possible to determine the amount of light received in any outgoing direction. This mapping is called the surface's BRDF (Bidirectional Reflectance Distribution Function). It assumes the ray will come out of the same point it reached the surface (no successions of micro bounces caused it to leave the surface at another point).
In traditional backwards ray tracing it is not practical to simulate diffuse bounces (when the ray leaves the surface in a random direction), simply because the lights rays are traced backwards (from the eye to the light). This makes ray tracing limited in the images it can produce. Any effect that involves a diffuse bounce before the light reaches the eye is not possible in standard ray tracing. Light rays have to be sent from both the eye and the light.
Photon mapping is an elegant way to solve this: before any standard raytracing is done, light (discretized as "photons") is sent from the light sources in the scene and allowed to bounce around, then stored in a "photon map". The photon map stores final positions of the photons as well as color and incoming direction. After the map is built, standard raytracing is done, and for each bounce the photons near the location of the bounce are essentially treated as small light sources. This allows to "complete" light paths that would not normally be considered. Photon maps are usually implemented using a kd-Tree (a form of axis aligned BSP-tree), to allow fast retrieval of neighbors around a point.
Algorithm: Given a total number of photons and a certain number of light emitters (and their area and power), generate photons one at a time, such that lights with higher power*area have a higher probability of generating a photon. Then, trace photons just like light rays, but at each bounce, assign a probability to each type of bounce (diffuse, specular, transmissive, absorbed), and send the photon on only one type of path (this is Russian roulette sampling). Probabilities are taken from the diffuse and specularity properties of the surface at the bounce location. Absorbed photons are just discarded.
Two main effects are simple to simulate when using photon mapping: caustics and diffuse interreflection (color bleeding). Therefore, two photon maps are created, one for each effect.
- Caustics occur when light is focused at a certain point: light goes through a number of specular bounces, only to reach a diffuse surface. To simulate this, in the algorithm the photon is allowed to make any number of specular bounces, but at the first diffuse bounce, it is stored in the photon map and another photon is generated.
Diffuse interreflections come from light that bounces around the scene, "grabbing" color at each step.
To simulate this, just like for caustics, photons are stored at each diffuse bounce, but are still allowed to continue on their
path, until they get absorbed.
(Care has to be taken not to include the caustics case inside the diffuse interreflection case. Before storing a photon in the diffuse map, we have to check to see if it has only made specular bounces before that, if so, it is a caustic photon and must not be stored.)
Photon mapping is simple to integrate into a ray tracer, and produces very realistic looking images. For more detail, see Henrik Wann Jensen's book "Realistic Image Synthesis Using Photon Mapping", and course notes from Brown.
One final note: photon mapping is a monte-carlo algorithm: the more photons sent the less biased the result (compare the first and third image). Also, as opposed to Jensen we had to grab the photons around a fixed radius (as opposed to a radius that expands as needed to grab a fixed amount of photons).