My goal for this project was to compare two different global illumination techniques for raytracers using the NVidia CUDA platform to parallelize computations on the GPU. While I wasn't able to completely implement both of the techniques, I was able to produce some interesting images nonetheless.

Photon Mapping

Photon mapping is the first approach that I attempted. Since it's a complex, multi-step process a significant amount of code is necessary to even begin to see results. I was unable to actually complete my renderer with this method of GI. Following is a description of the general steps of the process.

Step 1: Cast Photons

The first step involves casting photons from the lights. Photons are small packets of light represented by a position, direction, power, and color. Photons are cast from light sources in the scene in different directions based on the shape of the light source. They then bounce around the scene, following diffuse and specular Monte Carlo rules and also sometimes being transmitted or reflected in dielectric interactions. Photons have a chance of being absorbed at each surface they hit, and once absorbed they stop at that position. The random absorption allows the photons to be evenly distributed throughout the scene.

Step 2: Build kd-tree

The second step is performed for the sake of sheer speed. This step involves generating a kd-tree to hold the photons that have been cast into the scene. The use of a kd-tree allows for more effective gathering algorithms in the next step.

Step 3: Raytrace and Gather

Using the kd-tree and a K-Nearest-Neighbor search algorithmm, the nearest photons to a given raytraced point can be gathered and accumulated. This was a part that I had a lot of trouble with, because I could not find clear documentation on how the accumulated photons affect the point in question.


The images to the right are visualizations the locations of approximately 1000 photons cast into the scene. My photon casting algorithm was extremely simplified, causing a large number of photons to be cast outside the scene and relatively few to be visible in the scene itself. It's also evident that the photons don't fill the room very evenly wtihout a more complex casting algorithm.

Monte Carlo Path Tracing

Monte Carlo path-tracing involves a more parallel-friendly version of the standard recursive Monte Carlo approach. I was able to build a full implementation of the path tracing approach, despite occasional odd color bleeding behavior.


The path-tracing approach utilizes an averaged series of "passes". Each pass involves casting a ray for each pixel (or several for each pixel, for an anti-aliased image). Each of these rays bounces according to a Monte Carlo algorithm based on the properties of the object hit. These reflections are very similar to the photon behaviors described above.

More Passes, Smoother Picture

When the colors for each pass are averaged together, the randomness becomes smoothed out and the image's clarity increases, demonstrating the reflection, refraction, and color bleeding rules that define rays' behavior. The results show the same cornell box image composed of varying amounts of passes.


8 Passes

1k Passes

40 Passes

5k Passes

200 Passes

25k Passes