cdtwigg2.jpg (15524 bytes)

Project 3: Trace

Assigned: 10/28/2003
Due: 11/18/2003
Artifact: 11/21/2003

Project TA: Jonathan Schoeller
Email: jschoell_AT_cs.washington.edu


Quick Links

  1. .zip skeleton code + sample
  2. Just the Win32 sample raytracer, no skeleton
  3. Just the Linux sample raytracer, no skeleton
  4. Project roadmap
  5. Help-session docs
  6. .ray File Format
  7. Sample textures for texture mapping
  8. Simple sample scenes

Project Description

Trace is a program that constructs recursively ray-traced images of fairly simple scenes.

Getting Started

To install the starting point source code, grab the .zip distribution. In the "scenes" subdirectory, you'll find some sample scene files (all the files with the .ray extension). These are text files that describe some geometry and the coloring that should be applied to them. Also, we are making a collection of simple sample scenes available. Feel free to take a look at the notes from the help session.

Running the Sample

Before you begin coding, you should run the sample solution; it is included in the skeleton distribution as "sample_ray.exe" It has all of the requirements implemented, along with some extra features such as antialiasing, light strength controls and attenuation controls.

Creating Your Own Scenes

As you get into the project, you'll probably want to use some scenes of your own invention. For this you can either write your own .ray files, or you can use the modeler program from the last project to create them for you.

To use the modeler, run it and open your model like before. Adjust any sliders or widgets to values you like, then select the "Write raytrace file..." option from the file menu.

If you are interested in writing your own files from scratch, a help page on the file format is available. This file also describes the specifications of all the primitives you are required to implement.

Required Extensions

After running the sample solution, you should build the skeleton code and see how it compares. You will probably notice that there is a significant difference in the quality of images rendered with the two versions. This suggests what parts of the raytracer have been written and what parts are left undone.

If you compare the outputs of the skeleton and solution, you will see that most of the basic geometry-handling code is done. The skeleton code is able to cast rays into an image and draw color on the screen, resulting in some flat-shaded polygonal shapes.  The skeleton code is doing ray-casting and nothing more.  Furthermore, the sphere primitives will not appear. While all the code to cast a ray exists, not all of the object intersections code is there.  You need to implement sphere intersections and expand ray-casting into ray-tracing by adding support for reflected and refracted rays. You also must implement the Phong specular-reflection model.

Specifically, each person must implement recursive ray tracing as described in class. This entails making the following extensions to the program:

Extension Watt. Foley, et al. Glassner
Sphere Intersection pp. 18-19 15.10 pp. 91
Phong specular-reflection model 6.2-6.3 16.1 and 16.2.5 -
Contribution from:
  multiple light sources,
  distance attenuation,
  and these additional types of lights:
  • Directional lights
  • Point lights
(see lecture notes) 16.1 (particularly in 16.1.5 and 16.1.6) -
Opaque Shadows 9 16.12 and 16.4 -
Reflection 1.4 16.12 4.2.1
Refraction 1.4 (but see the errata!) 16.12 4.2.3 - 4.2.7
Note: Box intersections and anti-aliasing are NOT required for this project. The skeleton for these features is present in the skeleton code though, and each will be worth a whistle if implemented correctly.

Your ray tracer should recursively trace rays to account for the required extensions. Recursion should proceed to a maximum depth as set by the user.

Getting Started

The Trace project is a very large collection of files and object-oriented C++ code. Fortunately, you only need to work directly with a small subset of it. However, you will probably want to spend a bit of time getting familiar with the layout and class hierarchy at first, so that when you code you know what classes and methods are available for your use.

The starting point for where ray tracing begins, and where you will be needing to add a lot of functionality, is in the RayTracer.cpp file. This is a good file to start studying and exploring what methods get called and what they do.


Bells and Whistles

In many cases, the material in the Foley, et al. book goes into more depth on a particular subject than the Alan Watt text. In addition, Glassner's book on ray tracing is a very comprehensive exposition of a whole bunch of ways ray tracing can be expanded or optimized (and it's really well written). If you're planning on implementing any of these bells and whistles, you are encouraged to read the relevant sections in these books as well.

Remember that you'll need to establish to our satisfaction that you've implemented the extension! You should have test cases that clearly demonstrate the effect of the code you've added to the ray tracer. Sometimes different extensions can interact, making it hard to tell how each contributed to the final image, so it's also helpful (that is, necessary!) to add controls to selectively enable and disable your extensions.

[whistle] Implement an adaptive termination criterion for tracing rays, based on ray contribution.  Control the adaptation  threshold with a slider.

[whistle] Implement antialiasing by supersampling and averaging down.  You must provide a slider that indicates the number of sub-pixel samples being used (e.g., something in the range 1-5 indicating 1x1, 2x2, ... 5x5 supersampling). This whistle upgrades to a bell if you implement the first stage of distribution ray tracing by jittering the sub-pixel samples.  The noise introduced by jittering should be evident when casting 1 ray per pixel.

[bell]Allow colored shadows, that is, if you shine a light on a blue glass sphere, it should allow the blue light to pass through and hence cast a bluish shadow on the ground.

[bell] Implement spot lights.

[bell] Add a menu option that lets you specify a background image to replace the environment's ambient color during the rendering.  That is, any ray that goes off into infinity behind the scene should return a color from the loaded image, instead of just black.  The background should appear as the backplane of the rendered image with suitable reflections and refractions to it.

[bell]Find a good way to accelerate shadow attenuation.  Do you need to check against every object when casting the shadow ray?  This one is hard to demonstrate directly, so be prepared to explain in detail how you pulled it off.

[bell] Deal with overlapping objects intelligently.  While the skeleton code handles materials with arbitrary indices of refraction, it assumes that objects don't intersect one another. It breaks down when objects intersect or are wholly contained inside other objects. Add support to the refraction code for detecting this and handling it in a more realistic fashion.  Note, however, that in the real world, objects can't coexist in the same place at the same time. You will have to make assumptions as to how to choose the index of refraction in the overlapping space.  Make those assumptions clear when demonstrating the results.

[bell+whistle] Add texture mapping support to the program. The most basic kind of texture mapping is to apply the map to the diffuse color of a surface. But many other parameters can be mapped. Reflected color can be mapped to create the sense of a surrounding environment. Transparency can be mapped to create holes in objects. Additional (variable) extra credit will be given for such additional mappings.  The basis for this bell is built into the skeleton, and the parser already handles the types of mapping mentioned above.  Additional credit will be awarded for quality implementation of texture mapping on general trimeshes.

[bell+whistle] Implement antialiasing by adaptive supersampling, as described in Foley, et al., 15.10.4.  For full credit, you must show some sort of visualization of the sampling pattern that results.  For example, you could create another image where each pixel is given an intensity proportional to the number of rays used to calculate the color of the corresponding pixel in the ray traced image.  Implementing this bell/whistle is a big win -- nice antialiasing at low cost.

[bell+whistle] Implement more versatile lighting controls, such as the Warn model described in Foley 16.1.5. This allows you to do things like control the shape of the projected light.

[bell] [bell] Implement bump mapping (Watt 8.4; Foley, et al. 16.3.3).

[bell] [bell] Implement solid textures or some other form of procedural texture mapping, as described in Foley, et al., 20.1.2 and 20.8.3. Solid textures are a way to easily generate a semi-random texture like wood grain or marble.

[bell] [bell] Add some new types of geometry to the ray tracer. Consider implementing torii or general quadrics. Many other objects are possible here.

[bell] [bell] Add support for height-fields. Click here for a discussion on what they are and how they can be generated.  

[bell] [bell] for first, [bell+whistle] for each additional
Implement distribution ray tracing to produce one or more or the following effects: depth of field, soft shadows, motion blur, or glossy reflection (See Watt 10.6, Glassner, chapter 5, or Foley, et al., 16.12.4).

[bell] [bell] [bell] Add some higher-level geometry to the ray tracer, such as surfaces of revolution, extrusions, metaballs or blend surfaces.  You may have implemented one or more of these as a polygonal object in the modeler project.  For the Raytracer, be sure you are actually raytracing the surface as a mathematical construct, not just creating a polygonal representation of the object and tracing that.  Yes, this requires lots of complicated math, but the final results are definitely worth it (see Transparent Metaballs).  A really good tutorial on raytracing metaballs.

[bell] [bell] [bell] Implement ray-intersection optimization by either significantly extending the BSP Tree implemented in the skeleton or by implementing a different optimization method, such as hierarchical bounding volumes (See Glassner 6.4 and 6.5, Foley, et al., 15.10.2).

[bell] [bell] [bell] [bell] Implement a more realistic shading model. Credit will vary depending on the sophistication of the model. A simple model factors in the Fresnel term to compute the amount of light reflected and transmitted at a perfect dielectric (e.g., glass). A more complex model incorporates the notion of a microfacet distribution to broaden the specular highlight. Accounting for the color dependence in the Fresnel term permits a more metallic appearance. Even better, include anisotropic reflections for a plane with parallel grains or a sphere with grains that follow the lines of latitude or longitude. Sources: Watt, Chapter 7, Foley et al, Section 16.7; Glassner, Chapter 4, Section 4; Ward's SIGGRAPH '92 paper; Schlick's Eurographics Rendering Workshop '93 paper.

This all sounds kind of complex, and the physics behind it is. But the coding doesn't have to be. It can be worthwhile to look up one of these alternate models, since they do a much better job at surface shading.  Be sure to demo the results in a way that makes the value added clear.

Theoretically, you could also invent new shading models. For instance, you could implement a less realistic model! Could you implement a shading model that produces something that looks like cel animation? Variable extra credit will be given for these "alternate" shading models.  Links to ideas: Comic Book Rendering

Note that you must still implement the Phong model.

[bell] [bell] [bell] [bell] Implement CSG, constructive solid geometry. This extension allows you to create very interesting models. See page 108 of Glassner for some implementation suggestions. An excellent example of CSG was built by a grad student here in the grad graphics course.

[bell] [bell] [bell] [bell]Implement caustics.  Caustics are variations in light intensity caused by refractive focusing--everything from simple magnifying-glass points to the shifting patterns on the bottom of a swimming pool.  A paper discussing some methods, and some images

Implement Photon mapping, a powerful variation of ray tracing that adds speed, accuracy and versatility.  It's a two-pass method:  in the first pass photon maps are created by emitting packets of energy (photons) from the light sources and storing these as they hit surfaces within the scene.  The scene is then rendered using a distribution ray tracing algorithm optimized by using the information in the photon maps.  It produces some amazing pictures.  Here's some information on it.

Correctly model Sub-Surface Scattering, which is a useful technique for modelling translucent materials, or materials where light is scattered beneath the surface (such as skin, milk, plants... ). Check this paper out to learn more.

Implement Metropolis Light Transport, a Monte Carlo method that samples the light paths that are most likely to contribute to the scene, by randomly mutating known good paths and accepting the modified paths based on statistical criteria. Here's some information on it, and a neat picture.


There are innumerable ways to extend a ray tracer. Think about all the visual phenomena in the real world. The look and shape of cloth. The texture of hair. The look of frost on a window. Dappled sunlight seen through the leaves of a tree. Fire. Rain. The look of things underwater. Prisms. Do you have an idea of how to simulate this phenomenon? Better yet, how can you fake it but get something that looks just as good? You are encouraged to dream up other features you'd like to add to the base ray tracer. Obviously, any such extensions will receive variable extra credit depending on merit (that is, coolness!). Feel free to discuss ideas with the course staff before (and while) proceeding!