Home Page

Home Page

Comp 238

Programming Assignment 1:  "Classic" Ray Tracer

Page 1

Features

  • Simple scene description language (SDL)
  • Object-oriented design
  • Adaptive anti-aliasing
  • Shadows, reflections, and refractions
  • Spheres, planes, and triangles
  • Triangle meshes with hierarchical bounding volumes
  • Image textures with bilinear interpolation

Overview

This project represents a major upgrade to my Comp 236 ray tracer. It basically had sphere and plane primitives with shadows and reflections. I added transparency (i.e. refractions), triangle primitives, triangle meshes with hierarchical bounding volumes, and image textures with bilinear interpolation. I also implemented Whitted's anti-aliasing scheme. Lastly, I made some performance enhancements (e.g. pre-calculations to make intersection tests faster) and tracked down some memory leaks and other little bugs.

Transparency

Transparency is generally lumped in with reflections when talking about ray tracing. While they are handled the same at a high level, transparency is actually quite a bit more complicated. Like reflections, you basically just recursively spawn a new ray in the "proper direction." Unlike reflections, however, you then have to deal with being inside a transparent object. You must keep track of whether you are inside or outside objects, you must decide how to shade the inside surface of objects, and you have to ensure your normals are facing the right direction. You must also decide how complex transparent models can be (e.g. can you have a glass sphere embedded within another).

My code assumes that no two transparent objects may interpenetrate. That is, the code expects a ray inside a transparent object to exit into air (as opposed to possibly hitting a different transparent object). The Ray class contains a boolean that keeps track of whether a ray is outside all objects (the normal case) or is currently inside a transparent object. The shading routine does not calculate local ambient, diffuse, and specular contributions for inside surfaces, but it does spawn the appropriate reflection and refraction rays. An example image featuring a glass sphere is shown below.

Triangle Meshes and Bounding Volumes

In addition to demonstrating refractions with a glass sphere, the above image contains a triangle mesh object (the teapot). I added hierarchical bounding volumes (specifically sphere extents) because it was just taking too long to render. Basically, the top-level mesh holds a list of sub-meshes, and the extent at the top level encloses all sub-meshes. Each sub-mesh has its own extent and a list with possibly more sub-meshes further down the hierarchy. Meshes in the leaves have empty sub-mesh lists and contain the actual triangles.

When performing intersection testing, the ray is tested against the top-level spherical extent first. If it misses this, then it misses everything and no further testing is needed. This is a big win because the sphere test is simple and fast, and a miss potentially avoids thousands of (relatively) expensive tests on the individual triangles. If the top-level extent is hit, then the extents of the sub-meshes are tested. Only those triangles within extents that are hit are individually tested, so many tests can still be avoided even if the top-level extent is hit.

The above figure illustrates hierarchical bounding volumes with the teapot model. The image was created with some OpenGL code I quickly hacked together. The model was created by tessellating a bicubic bezier patch representation of the teapot. It contains 288 triangles per patch for a total of 9216 triangles. A simple way to use bounding volumes for a model created from bezier patches is to give each patch its own extent. This is shown in the figure for the highlighted patch and its corresponding highlighted bounding sphere. Note the top-level bounding sphere that surrounds the entire teapot. Returning to our previous discussion, if a ray hits the top-level extent but then misses the extent for the highlighted patch, then the 288 triangles comprising that patch will not be tested.

The above figure also illustrates the major shortcoming of spherical extents, which is that they are often not very tight fitting. This results in a high percentage of false alarms. However, they are relatively easy to implement, and the sphere intersection test is very efficient. Actual execution times for the image containing a glass sphere and a 9216-triangle teapot appear below. The screen size was 120x120, and the measurements were made on a P4-1.9Ghz with 256MB of RAM.

Teapot Model

Execution Time

Triangles only

150 minutes (2.5 hours)

Top-level extent only

78 minutes (1.3 hours)

Hierarchical extents

17 minutes (0.28 hours)

Email Jason Stewart