Project Description

Trace is a program that constructs recursively ray-traced
images of fairly simple scenes. It is similar in functionality to the POV-Ray raytracer
. You might try browsing around the POV-Ray web site for artifact and extra credit
inspiration. And POV-Ray can be downloaded for free, so if you want a taste of what a
really powerful raytracer can do, then go check it out!

Getting Started

To install the starting point source code, grab the starter package
. 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 material that should be applied to
them. Feel free to take a look at the roadmap
for a brief explanation. Though Windows is the preferred and
"officially supported" platform, the source should compile and run
under Linux, too. A Linux Makefile has been included with the project for
your convenience. If you do decide to work in Linux, please don't run
your Big Long Renders on the instructional machines (Fiji, Ceylon, etc).
If you do, be sure to nice your process or support's zombie-bots may kill it.
It is also possible to run this code on Mac OS X, but if you want to try that
you are completely on your own, so we wouldn't recommend it.

NOTE: MSVC 7.0 (aka .NET) is installed on all undergraduate lab machines. Using .NET is recommended as this is the platform the code was most recently tested on.
If you plan to work from home or in Linux, more complete setup directions can be found here.

The Trace project is a very large collection of files and object-oriented
C++ code. Fortunately, you only need to work directly with a 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. In addition, the raytracer features a debugging window that
allows you to see individual rays bouncing around the scene. This window
provides a lot of visual feedback that can be enormously useful when debugging
your application. Look at this web page for a detailed explanation of how to use
the debugging window.

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.

Creating Your Own Scenes

As you get into the project, you'll probably want to use some scenes of
your own invention. There is a help page available about the file
format. This file also describes the specifications of all the primitives
you are required to implement. To create realistic refractive objects,
you'll need their Indices
of Refraction.

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 box and 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 and box
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 and include support for transparent objects.

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

Your ray tracer should recursively trace rays to account for these.
Recursion should proceed to a maximum depth as set by the user. For the antialiasing
requirement, you can simply use the method of supersampling and averaging down. Doing
adaptive supersampling is an extra credit option as described below. You should be
able to turn your antialiasing on and off like the sample raytracer.

NOTE: You may assume that objects are not nested inside other objects. If a refracted ray
enters a solid object, it will pass completely through the object and back outside before
refracting into another object. Improving your refraction code to handle more general
cases such as a refractive sphere contained inside another refractive sphere is an
extra credit option as described below. In addition, you may assume that the camera
itself is not placed inside an object. The initial rays that are sent out through
the projection plane will always be moving through air.

NOTE: Alan Watt's book is full of errors, be sure to check out this errata before blindly trusting any of the equations.

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.

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

Modify your antialiasing to
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.

Implement spot
lights.

Improve your refraction
code to allow rays to refract correctly through objects that are contained inside other objects. You must put
together a .ray file to demonstrate this effect.

Add
code for triangle intersections. Some of this is already done for you in
trimesh.cpp, and doing this can add a lot of functionality to your program. You need to
implement this in order to view any of the scenes in the scenes\polymesh directory.

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. This is also called environment mapping. Click here for some examples.

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.

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.

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.

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.

Add texture mapping support to the program. To get full credit for this, you must add texture mapping support
for all the built-in primitives (sphere, box, cylinder, cone) except trimeshes. The square object is already done
for you.
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.

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. Click here for a tutorial on making realistic looking marble using Ken Perlin's noise function.

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

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

for first,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).

Add some higher-level
geometry to the ray tracer, such as surfaces of revolution, extrusions,
metaballs, swept surfaces, 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).
Here is a really good tutorial
on raytracing metaballs. For an additional bell, add texture mapping to your higher-level
geometry. The texture mapping must look good in order to get credit for it!

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).

Implement
3D fractals and extend the .ray file format to provide support for these objects. Note that
you are not allowed to "fake" this by just drawing a plain old 2D fractal image, such as the usual Mandelbrot Set.
Similarly, you are not allowed to cheat by making a .ray file that arranges objects in a fractal pattern, like the sier.ray test
file. You must raytrace an actual 3D fractal, and your extension to the .ray file format must allow you to control the resulting
object in some interesting way, such as choosing different fractal algorithms or modifying the base pattern used to produce
the fractal.

Here are two really good examples of raytraced fractals that were produced by students during a previous quarter:
Example 1,
Example 2
And here are a couple more interesting fractal objects:
Example 3,
Example 4

Implement
4D quaternion fractals and extend the .ray file format to provide support for these objects.
These types of fractals are generated by using a generalization of complex numbers called quaternions. What makes the fractal really interesting is that it is actually a 4D object. This is a problem because we can only perceive three spatial dimensions, not four. In order to render a 3D image on the computer screen, one must "slice" the 4D object with a three dimensional hyperplane. Then the points plotted on the screen are all the points that are in the intersection of the hyperplane and the fractal. Your extension to the .ray file format must allow you to control the resulting object in some interesting way, such as choosing
different generating equations, changing the slicing plane, or modifying the surface attributes of the fractal.

To get started, visit this web page to brush up on your
quaternion math. Then go to this site to learn
about the theory behind these fractals. By now you should have a high level overview of what's going on, so you are ready to
take the plunge and dive into this hardcore web page, which contains
a practical discussion of how quaternion fractals are implemented in POV-Ray.

Here's a movie of a quaternion fractal spontaneously appearing in our own Suzzallo library!

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.

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.

Add a particle systems simulation and renderer (Foley 20.5, Watt 17.7,
or see instructor for more pointers).

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.

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!

Disclaimer: please consult the course staff before spending any serious
time on these. These are all quite difficult (I would say monstrous)
and may qualify as impossible to finish in the given time. But they're cool.

Sub-Surface Scattering

The trace program assigns colors to pixels by simulating a ray of light
that travels, hits a surface, and then leaves the surface at the same
position. This is good when it comes to modeling a material that is
metallic or mirror-like, but fails for translucent materials, or materials
where light is scattered beneath the surface (such as skin, milk, plants... ).
Check this
paper out to learn more.

Metropolis Light Transport

Not all rays are created equal. Some light rays contribute more to
the image than others, depending on what they reflect off of or pass through
on the route to the eye. Ideally, we'd like to trace the rays that have
the largest effect on the image, and ignore the others. The problem
is: how do you know which rays contribute most? Metropolis light
transport solves this problem by randomly searching for "good"
rays. Once those rays are found, they are mutated to produce others that
are similar in the hope that they will also be good. The approach uses
statistical sampling techniques to make this work. Here's some information
on it, and a neat picture.

Photon Mapping

Photon mapping is 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.

Also, if you want to implement photon mapping, we suggest you look at the
SIGGRAPH 2001 course 38 notes. The Ta's can point you to a copy, if you
are interested.