COMP 870 - Assignment 3


Aims | Current state | Simulation results and Discussion | Source code and binaries | References | email: golas at cs dot unc dot edu |

This assignment had the following aims:


Current state:

I've used the photon map approach to add global illumination support to the ray tracer.

The photon map approach is a simple two pass approach to global illumination. The first pass is a forward photon tracing pass. Photon tracing is the same as ray tracing, hence the same architecture can be used for this pass. Photons are emitted from all light sources in the scene, and traced throughout the scene. The only difference from ray tracing is that the originating "photon rays" originate from light sources rather than from the camera, like what is known as "forward ray tracing" (albeit, in more recent terminology, in older terminology, it's backward rt). The so-called photon rays can undergo the same scene interactions as light rays, like specular and diffuse reflections, refractions, and in addition, can get absorbed by the surface. At each interaction we store a copy of the photon to be used in the second pass. For storing photons, we use 2 photon maps, a caustic map for storing photons which have undergone specular reflections and refractions only, and a global map for all other photons. The primary difference between photon tracing and ray tracing is that instead of spawning multiple rays for each interaction, we do a Russian Roulette to choose which interaction to pursue further. The tracing algorithm can be expressed as follows:

algorithm photon_trace {
        Until enough photons are stored {
                Pick a light source and generate photon
                At each step {
                        If number of intersections of current photon > 1 {
                                If photon has only encountered specular reflections or transmissions -> Store copy in caustic map
                                Else store in global map
                        Do Russian Roulette: Generate random number r in the range [0,1]
                        If r < kt (transmission coeff) -> Refract photon ray
                        Else if r < kr + lr -> Reflect ray {
                                Generate a new random number r' in the range [0,1]
                                Get probability of Specular reflection Ps, and Diffuse reflection Pd
                                If r' < Pd -> Diffuse reflect after sampling random direction after appropriate power scaling
                                Else if r' < Pd + Ps -> Specular reflect after appropriate power scaling
                                Else Absorb photon
                        Else Absorb photon (end iterations on this photon)


For emitting photons, I've made a simplifying assumption that all light sources are of the same power. This allows me to use a simple round robin system to choose which light source to emit from, rather than use a complicated probability distribution to ensure fairness and conform to the actual physical phenomena. To emit photon from a light source, the direction is sampled as a point on the surface of a unit sphere. Since I have not added directional light sources, this scheme is sufficient. For point lights, the source of the photon ray is the location of the point light, while for area lights, the source is sampled on the light source disk.

The second pass of the photon map algorithm involves rendering the scene using the photon map. A Kd-tree is used to optimize nearest neighbor search that is required to get photons to retrieve the global illumination. For gathering photons, I use a recursively increasing search radius method as used in MegaPOV, which starts with a low search radius, and successively increases the radius if the desired number of photons are not found. The radiance estimate for a point on screen can be shown to be:
            L = Direct Illumination + Specular/glossy reflection + Diffuse reflections + Caustics + Refraction
The direct illumination, specular reflection and refraction components can be efficiently computed by using conventional ray tracing methods, and hence we do not use photon maps for them. However, diffuse reflections and caustics are calculated by taking samples from the global and caustic maps respectively.


Simulation results and Discussion:

To illustrate the global illumination calculation, we can look at the following component images:

 + +    +    +    = 
      Direct               Specular              Diffuse                Caustics               Refraction                 Final
      7.33s                 13.22s               41.65s                  138.95s                 6.98s                    191.74s

The original image without global illumination is:

This was rendered in 15.78 seconds when checking till 10 reflections and refractions. The scene is a modified Cornell Box, in which there is 1 transparent and specular sphere each. The transparent sphere has the refractive index of glass. The light source is a point light source and is placed on the left wall. The scene shown above used just 1000 caustic and global photons each, with 10 photons per sample. For these photons, 100227 photons were shot, in 0.145 seconds.

From the implementation, I observed that photon mapping is a relatively easy to implement, albeit slow, but very powerful global illumination algorithm. But faster implementations exist, and parallel implementations can make it feasible to use the method. The only downside is the memory requirement for rendering high quality scenes. Moreover, getting the right scaling parameters for photon gathering can be difficult in practice when using filters to improve quality, for example the gaussian or cone filter. However, using a gaussian filter with photon gathering can be used to create somewhat artistic, and interesting artifacts:

Artistic rendering using global illumination


Source code and binaries:




Site last updated: Monday, September 8, 2008 12:00 AM