COS 526, Fall 2014
Assignment 1: Photon Mapping
Nikhilesh Sigatapu

Photon emission

The flags -nphotons and -ncaustic_photons control, respectively, the total number of global photons and caustic photons emitted from light sources in the scene. Point light sources emit uniformly in all directions. For area light sources, a point is chosen uniformly at random in the disk, then a direction is chosen in a distribution weighted by cosine of angle from normal. Directional lights shoot photons from a large enough disk outside the scene, with points chosen uniformly. For spotlights, the direction is chosen from a distribution similar to the one described by Jason Lawrence for importance sampling in specular Phong, with angles outside the cutoff rejected.

Below are some illustrations. Photon paths are shown by line segments. Only photons that actually hit a surface are shown. Each light type has two illustrations, one with a single light source and another with three light sources of different colors. In all cases the subject is a sphere on a box. At times the lines appear dotted or broken but this is simply due to aliasing in the image -- the actual path is continuous.









Photon scattering, Russian roulette and BRDF importance sampling

When a photon hits a surface, Russian roulette is used to determine the next step. A secondary ray is shot in either a diffuse, specular or transmission direction, or the photon is 'absorbed' and no secondary ray is shot. The probability of each event is determined by the properties of the material.

The diffuse and specular scattering distributions are based on Jason Lawrence's notes (BRDF importance sampling). Below an incident direction is shown in red, along which many photons are shot to produce the blue scattered directions.

Diffuse scattering

Specular scattering

Specular scattering, different viewpoint

For transmission we just propagate in the single refraction direction. Below a bunch of photon paths are focused into a caustic patch by a transparent ball (the ball is invisible in the image).


As this process is repeated, the photons bounce around the scene. Below are illustrations for photon paths up to depth 3 in cornell.scn and specular.scn (the spheres in specular.scn are rendered approximately as low-poly meshes, hence the gaps between their surfaces and the reflection points).

Scattering in cornell.scn

Scattering in specular.scn

Photon storage, photon map visualization

Photons are stored in a kd-tree. Their position, direction and power is saved. Below is a visualization of stored photons for some scenes. The photons are visualized with a color slightly brighter than the power actually stored for easier viewing, and have a short tail that indicated the (negative) incident direction.

cornell.scn (10000 global, 2000 caustic)

cornell.scn (50000 global, 5000 caustic)

specular.scn (50000 global, 5000 caustic)

specular.scn (100000 global, 10000 caustic)

Multiple photon maps

Two separate photon maps are generated, in separate passes. One is the usual global photon map, the other is the caustic photon map for which the first bounce must be a specular reflection or a transmission. The number of photons generated for each can be varied separately.

cornell.scn (global photon map)

cornell.scn (caustic photon map)

cornell.scn (both)

caustic.scn (global photon map)

caustic.scn (caustic photon map)

caustic.scn (both)

Camera ray tracing, radiance estimation

To produce the final image, rays are traced from the camera. At each surface intersection, the direct illumination (check shadow ray, then do a phong lighting calculation), specular/transmission (trace secondary rays), caustic (use the caustic photon map) and indirect illumination (use the global photon map) contributions are computed and combined.

Here are some illustrations of each part in cornell.scn:

cornell.scn (direct, specular/transmission)

cornell.scn (caustics)

cornell.scn (indirect)

And here is the final render, combining all parts:

cornell.scn (all)

Some other scenes:


softshadow.scn (with 4 rays per pixel, see below)

Pixel Integration

Multiple rays are shot through each pixel for raytracing (following a grid pattern per pixel), then the results are averaged to give the final color of the pixel. Below is a comparison at various multiplicities:

1 ray per pixel

4 rays per pixel

9 rays per pixel

Zoomed in:

1 ray per pixel

4 rays per pixel

9 rays per pixel

Ray tracing visualization

Rays traced during the camera ray tracing step can be visualized as white lines with the -viz_rays option. Below are illustrations of rays traced in the cornell.scn, specular.scn and caustic.scn scenes.




Kd-tree optimization

The given R3Kdtree class uses a naive sorted array to collect the N closest points asked for. I implemented an alternative member function, FindClosestQuick() which uses a max-heap instead (as provided by std::priority_queue in the C++ standard library). This is suggested on page 35 of the jensen01 reading. Further, I made an optimization that assumes that the position field of R3Kdtree elements is at the beginning of the struct, which eliminates the need for a callback function or for offsets (effectively, the offset becomes zero).

This provides a considerable speedup. The render time of the following scene was reduced from 21.30 seconds (using the given R3Kdtree) to 10.01 seconds (using my optimized method).

For comparison, the optimization can be turned off by providing the -slow_kdtree option to photonmap.


Art Contest Submission

I made a short video of a scene that looks like the cornell box, with the glass sphere starting in the air, fall onto the floor then rolling to the side (the box is slightly tilted). The animation was made with Blender. The frames were exported to .scn using the plugin for Blender which is included as art/

Each frame scene is also already provided as frame1.scn, frame2.scn and so on till frame250.scn under the art/ directory. The rendered frames are also provided as .bmp files. The frames were stitched together to produce the final video, art/art.mp4.

Here is a link to the video.

Here is a screenshot from the video: