15-864 Assignment 3: Photon mapping


In this assignment, you will learn about monte carlo sampling for solving the rendering equation and acceleration techniques.


The assignment description can be found in PDF form here. There is also this project roadmap. Let us know if you have any questions.

Rendering Contest

There will be a rendering contest at the end of the assignment.


We are providing you with a large code base to start from that should be of significant help. It can be found at /afs/cs.cmu.edu/academic/class/15864-s05/photonMappingStarter2005.tar.gz (due to the restrictions noted below, we cannot post it on the web).

The code will build under both Linux and Windows. The Linux Makefile should already point to all the correct libraries which have been installed in /afs/cs.cmu.edu/academic/class/15864-s05. For the Windows version, you will need the following libraries:

To save you the trouble of building all this, I have placed the file photonMappingLibrariesWindowsVS71.zip in the class directory (/afs/cs.cmu.edu/academic/class/15864-s05), just unzip it and point Visual Studio toward the appropriate directories. Those who prefer to roll their own (or are using an older version of VS.net) can obtain the correct versions of both GSL and VL in the class directory by themselves, FLTK and boost can be retrieved from their respective websites.

Note: Please do not distribute this code. Various portions of this code are provided courtesy of the University of Washington graphics group and Henrik Wann Jensen, and they have requested that we make it available only for the purposes of this class.


The major components of the code consists of (1) a parser, which converts .ray files into scene graphs, (2) a user interface, which you can use to adjust various ray tracer parameters and also to visualize the scene, and (3) the actual ray tracer implementation itself, which is a full recursive ray tracer in the style of Whitted.

The parser

The parser reads in .ray files, which are unfortunately a rather proprietary format, but which luckily support most of the stuff you would hope for including nested transforms, full scene graphs, arbitrary Phong materials and texture mapping, etc. The full documentation for this format is available here, but the best way to learn is by looking at the supplied samples. In particular, pay attention to the various Cornell box scenes that can be found in the scenes/photonMapping directory in the source code distribution.

The user interface

The user interface for the ray tracer uses the Fast Light toolkit. This is a cross-platform toolkit that allows for the use of OpenGL. It's also a little bit ugly (both in terms of the code you write and the look of the interface) compared to e.g. QT but its license is significantly less encumbered.

I have provided a couple of buttons and sliders in the UI for supporting both photon mapping and distribution ray tracing. In particular, you can select how many samples you want to cast per pixel (use the "samples/pixel edge" slider) and how many photons to send into the scene (use the "photons/light source" slider). The "Recompute photon map" button calls the recomputePhotonMap() function in Scene, which you have to implement. If you need to add any more sliders, you should add them in the GraphicalUI constructor and have an appropriate callback function (use the existing sliders/buttons as examples). Full documentation for FLTK 1.1 is also available on their web site.

The second (and most glamorous) part of the user interface is the debugging view, which you should hopefully find very useful. Most of the code that you might want to touch is in the DebuggingView::draw() function. A write-up giving more details for this interface can be found here.

The ray tracer

Most of the action in the ray tracer itself happens in the RayTracer::traceRay function. This implements a full recursive Whitted ray tracer with reflection and refraction and you should use this code as a reference while you are working on extending it to handle photon mapping. In particular, it makes extensive use of the Scene::intersect function, which casts a ray into the scene and returns with both the location of the intersection, a pointer to the intersected object, and the surface material.

The RayTracer::tracePixel function samples the pixel using stratified sampling as a proper distribution ray tracer should. It calls RayTracer::traceRay to get irradiance estimates for a given ray direction.

For other details on the code, please see this code roadmap.

At center, the photon map for the Cornell box scene; at left, rendering the scene using the 2-pass algorithm suggested in Henrik's book; at right, the "official" rendering of the Cornell box, from this page. I'm not sure what is causing the differences between my box and the official rendering, but I suspect they are in part due to our use of a very simple RGB color model as opposed to a proper spectral model.

The Photon Map

Henrik has graciously provided us with his photon map implementation. You can find it in photonmap.h and photonmap.cpp. All the documentation we have for this is in the header file; more details may appear later.


I will periodically be adding assignment tips below.