Project 2: Ray Tracing
Due Dates:
This assignment is worth 100 points. See the course web page for the
intermediate and final project due dates.
You get two late days for this assignment. These days (and any left over from project 1)
will be used extend intermediate or final deadlines as needed.
Failure to meet any (possibly extended) deadline incurs a cost of 5 points per day until
the work is completed.
You are strongly urged to work early and often!
Overview
In this assignment you will implement a basic raytracer.
The program reads the description of a 3D scene from a
ray file and produces
a rendered image of that scene. The program works in interactive and
batch mode.
We provide skeleton code and a host of support classes to help you get started.
We also provide a solution executable to help you test and debug your code.
A gallery of images created by previous semesters of this class is
maintained here for motivation.
What You Have to Do
Following is a road map for the project.
Download the skeleton code (here)
and the sample executable.
(25 pts.) Ray Casting :
The first step is to construct a simple ray-casting system (25 points).
Your
program will casts rays into the scene and find the closest intersecting
object (triangle or sphere).
- (10 pts.) Cast rays into the scene:
Modify RayFile::raytrace() to generate rays from the
camera's position through each pixel of the image.
Review the UML diagrams to understand the RayFile class and how to
access the information needed to compute these rays.
-
(10 pts.)
Intersections with spheres: Modify Group::intersect() and
Sphere::intersect() to compute intersections between the ray and
a sphere.
Review the UML diagrams to understand the Group and Shape
classes. These hold the scene graph described by the input ray file.
Ignore group transforms for now.
(Test file: 1.sphere.ray.)
Information about the intersection point is passed using the _Intersection_
structure, which is described in intersection.h. The intersection routines
return the distance from the start of the ray to the interesection point.
Remember, you want to find the closest intersection point that is in front
of the camera!!
At this stage you can start to render images with white circles
by setting pixel (i,j) white if an intersection was found and black otherwise.
-
(5 pts.)
Intersections with triangles: Repeat the same step for triangles,
this time modifying Triangle::intersect().
(Test file:
2.triangle.ray)
(10pts.) Transformations:
In this step you'll introduce transformations. Modify Group::intersect() to take into
account its local transformation. Use the transform information to convert the ray
into local coordinates, find the closest intersection, and use the
transform information to convert the intersection back into the parent node's coordinates.
Be careful when converting the normal!
Also, be sure to re-compute the distance to the intersection point
in the parent node's coordinates.
(Test file:
3.xfm.ray)
(25 pts.) Color:
The next step is to compute the color at the intersection point.
- (2) Emissive:
Modify RayFile::getColor() to calculate color using the intersecting
surface's emissive properties.
(Test file: 4.emissive.ray)
- (3) Ambient:
Modify RayFile::getColor() to calculate color using the intersecting surface's
ambient properties and the ambient light in the scene.
(Test file: 5.ambient.ray)
- (7) Directional Lights: Implement
DirectionalLight::getDiffuse(), DirectionalLight::getSpecular(), and
DirectionalLight::getShadow() to calculate the effect of directional
lights on the scene.
Modify RayFile::getColor() to call these functions.
Note: this has been implemented for you!
(Test file: 6.dirLight.ray)
- (8) Point Lights: Implement PointLight::getDiffuse(),
Point::getSpecular(), and PointLight::getShadow() to calculate the
effect of point lights on the scene.
Modify RayFile::getColor() to call these functions. Note: make sure
this works before moving on to spotlights.
(Test file: 7.pointLight.ray)
- (8) Spot Lights: Implement SpotLight::getDiffuse(),
SpotLight::getSpecular(), and SpotLight::getShadow() to calculate the
effect of spotlights on the scene.
Modify RayFile::getColor() to call these functions. (Test file: 8.spot.ray)
(5 pts.) Texture mapping: Add texture mapping. Modify Triangle::intersect() and
Sphere::intersect() to calculate texture coordinates at the point of
intersection. Modify RayFile::getColor() to use the texture
color as the diffuse factor in the color calculation. Add getTexture(u,v) to the material class.
Use bilinear interpolation for the texture samples.
(Test files: 8.spot.ray,
texture file)
(25 pts.) Recursive Ray Casting:
Next you'll extend your system to recursively cast rays (25 points).
- (10) Reflection: Modify RayFile::getColor() to recursively
cast reflected rays at the point of intersection and then use this value
in the color calculation. Be careful to offset the reflected ray slightly,
so you don't re-discover the same intersection point.
(Test file: 9.reflect.ray)
- (10) Transmission Modify RayFile::getColor() to recursively
cast transmitted rays at the point of intersection and then use this value
in the color calculation. For now, ignore the refractive index.
- (5) Snell's Law : Modify RayFile::getColor() to use the index of
refraction and Snell's Law to calculate the correct direction of
transmitted rays through objects.
(Test files: 10.refract.ray,
11.refract.ray 11.refract.bmp.)
Extensions:
Following are list of possible extensions to your ray tracer.
(5) Bump Mapping - add support for bump mapping for triangles and spheres.
(10) Procedural Textures - add support for 3D procedural
textures. Check out this
website for information on Perlin Noise.
(5) Jittering - implement a jittered supersampling technique to reduce
aliasing by casting multiple rays per pixel, randomly jittered about the
center of the pixel, and averaging the colors.
(5) Soft Shadows - treat each point and spot light as having some
finite volume and cast multiple rays for shadow tests. Modify
PointLight::getShadow() and SpotLight::getShadow() to return doubles
instead of booleans, and to return the average of these multiple shadow
tests. If you want, you can modify DirectionalLight:getShadow() to behave
similarly, but because a directional light doesn't have a position, good
results can be difficult to get.
(5) Box Primitive - add support for a Box primitive
(5) Cylinder Primitive - add support for a Cylinder primitive
(5) Cone Primitive - add support for a Cone primitive
(10) Torus Primitive - add support for a Torus primitive
Hard!
(5) Depth of Field - implement depth of field camera effects
(5) Fisheye Lens - implement fisheye lens camera effects
(10) Bounding Boxes - speed up raytracing by implementing bounding
boxes. Create a bounding box class and modify each object so it knows
about its own bounding box for intersection testing.
(?) Impress us with something we hadn't considered
(5 max) Submit an entry to the art contest.
Create an interesting model and ray trace it with your program.
(The operative word is interesting!)
You must submit the model to receive points.
(10 max) Submit an interesting MPEG movie made from multiple raytraced images.
You also have to submit the
sequence of commands used to created the images.
What to Submit
You should submit:
-
your windows project folder for rt,
-
an html writeup called "assignment2.html" that describes all features (or contest entries) you've
implemented along with links to images that demonstrate each feature and their associated ray file.
Make sure the source code compiles and runs on the
LAC PC's.
If it doesn't, we will not be able to grade your submission and it
will not garner any points!
Remember our standing late policy and collaboration policy.
Notes
Links
Last Update: 9/5/05