A Cornell Box was rendered using Photon Mapping and Ray Tracing techniques. Simulations show the effect of photon density on the quality of the rendered image. Specifically, increasing the number of photons used in the simulation yeilded more accurate images, however, this accuracy came at a cost of dramatically increased computation time. The number of photons used in deriving the radiance estimate at an arbitrary point in the scene also contributed greatly to scene accuracy and computation time.
The task of this assignment was to render a simple scene (i.e. Cornell Box) using one of two photorealistic rendering techniques: Photon Mapping or Radiosity. I chose Photon Mapping to calculate the global illumination in the scene as simple Ray Tracing to render the result. The Photon Map was implemented according to Jensen (2001, Appendix B) while the Ray Tracer implementation follows guidelines and algorithms in Glassner (1991) and Watt and Watt (1992).
My version of the Cornell Box scene consists of a cube bounding volume, one spherical object and one cube object. The left bounding surface was red, while the right was green. The remaining bounding surfaces were Light Goldenrod (RGB: [238, 232, 170]) except for the viewing (front) surface, which was black. The sphere object reflected the color green and the cube object yellow. All surfaces were considered diffuse reflective surfaces. No specular reflection, transmission, or refraction was modelled. In addition, no caustics were simulated, although photon mapping can be easily implemented such that caustics are accurately modeled. A square area light located on the top face of the bounding cube was the only light source in the scene.
I developed many graphic primative C++ classes for use in the mdoel scene. These classes described the following: Boxes, Bounding Boxes, and Spheres. Each type of object required its own ray tracing intersection class. A Ray class was also implemented forming the basis for the Ray Tracer used in this simulation. Specifically, the Ray class contained methods for calculating the intersection point of a Ray with any of the implemented object primatives. These algorithms were taken from Glassner (1991, Ch. 2) and Watt and Watt (1992).
The Photon Map was implemented directly from Jensen (2001, Appendix B). His implementation created a PhotonMap class containing the following methods: store photons in a kd-tree, balance the tree, estimate radiance via tree search. I extended this class to include a few accessors, specifically those to return the number of stored photons and the photon list itself. These accessors were useful in directly visualizing the photon map. I used my ray tracing methods to trace photons emitted from the square light source through the scene and stored photon (when appropriate) using Jensen’s Photon Map data structure. An outline of my implementation follows below:
The figures below are final photon map/ray traced renderings of the Cornell Box environment described above. The first set of images Figure 1 represents 100,000 photons with 100/300 photons within a 0.05 radius in the radiance estimate. The second set of images, Figure 2 represents 4 million photons with 100/300 photons within a 0.05 in the radiance estimate. Last, Figure 3 represents 6 million photons with 500 photons within a 0.5 radius in the radiance estimate. The computation/rendering time increased from about 30sec for the first set, to about 1-2 minutes for the second set and over 5 minutes for the last. A simple raytraced image is displayed in Figure 4 for comparison.
The number of photons used in the simulation greatly increased the accuracy of the final rendered image. As demonstrated by the figures below, a large number of photons (N > 100, 000) are needed to render a good quality image. The other main factor for generating quality images is the number of photons used in determining the radiance estimate at a point. The more photons used, the more accurate an estimate. From my simulations, at least 300 photons must be used for a good estimate (but more is better). Last, increasing the search radius around the intersection point for photons to use in the radiance estimate also increases the quality of the image. However, there is a limit to this benefit as only the closest photons are used.
Each parameter discussed above increases image quality. However, increasing those parameters has the effect of increasing the time needed to compute the photon map, or calculate the radiance estimate. In addition, using large numbers of photons is not feasible with computers/graphics cards having small amounts of memory. Also, including large numbers of photons in the radiance estimate is not recommended for large image resolutions. For instance, to render a 1024x1024 pixel image of the scene requires a radiance estimate calculation for over 1 million points. Despite the efficiency of searching a kd-tree, the lookup time and radiance calculation would take a very long time.
My particular implementation of photon mapping does not include caustics or specular reflections. Given more time, I would include these aspects of the lighting equation to obtain a more accurate rendering of the scene. Without the inclusion of caustics, this method loses one important advantage over other global illumination methods, such as radiosity.
p3.cpp: Main file with functions for combining Photon mapping with Ray Tracing.
RtObject.cpp: Base graphical primative class from which all others are extended
Box.cpp: Class for cube object
BoundingBox.cpp: Bounding Volume class, extended from Box class
Sphere.cpp: Class for sphere object
Intersection.cpp: Class for storing ray-object intersection information
BoxIntersection.cpp: Intersection class extension with storage for Box/BoundingBox-specific parameters, such at surface normal at intersection point
SphereIntersection.cpp: Intersection class extension with storage for Sphere-specific parameters
Vector.cpp: Class and methods for performing simple vector arithmatic (dot product, cross product, scalar multiply, etc)
PhotonMap.cpp: Class implementation of photon map data structure, from Jensen (2001, Appendix B)
Ray.cpp: Class implementation of Ray structure for ray tracing. Includes methods to calculate intersection points geometric primatives: Box, BoundingBox, and Sphere
jpegUI.cpp: Interface with JPEG library for image output
brumberg-3.tgz: Tarball of all assignment source files
This project was compiled on an AMD x86˙64. The above files require libgl, libglu, libglut, libjpeg and libm. The makefile will work on Windows systems running Cygwin.