Rendering Techniques Assignment 1:
Writing a Ray Caster
Assigned: Monday, September 20, 1999
Due: Monday, October 4, 1999
(before
the start of class - no extensions)
Overview
For this assignment, you will write your own ray casting program. Your
program will be capable of rendering Phong-illuminated, shadowed spheres.
You will be developing the program entirely from scratch, so be prepared
to get your hands dirty. If all goes well, you will achieve very satisfying
results and produce some pretty pictures of your own design.
The program should be written in C++. I will be compiling and
running your programs using g++, so whatever platform you use to develop
it, it should make sure it compiles and runs correctly with g++ before
you turn it in (that will put your instructor in a good mood just before
grading your assignment).
You might want to take a look at Paul Heckbert's “Writing a Ray Tracer,”
which is Chapter 7 of Glassner's An Introduction to Ray Tracing,
on reserve at MSE. If you read it, pay special attention to section 3,
and try not to be overwhelmed by the number of possible options and optimizations
for a ray tracer. You do not have to do things exactly as presented
in the article of course; it’s just a model in case that is useful.
Design your program in an object-oriented fashion from the start - we
will be making extensions to this program in future assignments. You should
have simple classes for vectors, rays, images, and rendering objects (sphere
is child class) as a minimum. Do not get too carried away using all possible
C++ features. Just keep it simple. Note that the vector class is important.
I don’t want to see you doing your vector computations one component at
a time, which leads to more code, more bugs, and more difficult reading
for your instructor. Be safe – use vector addition, subtraction, dot product,
cross product, scaling, and normalization functions (inline, if you care
about speed).
Program Description
The ray caster will read a simple scene description from an input file
(format specified below). It will support spotlights and spheres,
using Phong illumination (single-sided). You may specify all your
lights and spheres directly in eye coordinates, so you do not need to perform
any transformations. This is a ray caster, so you do not need to
trace reflection or transmission rays. However, I would like you
to trace shadow rays. Because there is no transparency, each light
is either fully visible or occluded to a particular surface point.
The program should create a PPM format image file (described below), which
is easy to generate. Typical programs for viewing .ppm files on Unix systems
include ‘xv’ and ‘display’. You should convert your files to lzw-compressed
tiff files to save space (saves space in your account, and smaller for
you to submit to me). The pbmplus set of utilities include the program
pnmtotiff. Freeware programs to view/convert .ppm files under Windows may
be found at: http://perso.wanadoo.fr/pierre.g/download/viewer/Xnview-gb-win.zip.
If you find other useful tools, let me know and I’ll pass the information
on to the rest of the class.
The executable should be called `raycast` and should be callable with
the simple command:
raycast <scene description filename> <image output filename>
(If it's useful to you, you could also consider allowing the input file
to come from stdin and the output file to go to stdout, but you must support
the above form as well.)
Included with this homework assignment is a sample
scene description and the corresponding rendered image. You should
test your program on this file as well as many other test cases you devise
to ensure that your program functions properly in all tricky circumstances.
Place some lights and spheres in an interesting arrangement to create
an image at a moderate resolution (512x512, perhaps). I will obviously
try some my own scene descriptions to test out your program.
You do not need to perform speed optimizations.
Suggested Approach
Here’s one path you might take to completing the project. I don’t want
to see all the intermediate results of these steps, but this should give
you an idea of how I would approach the project.
-
Start early. I have given you enough time for this assignment,
but it will take you the entire time. Starting early will
give you time to ask me questions about those crucial details that you
didn’t even realize existed until you tried to write the program. Remember
– no extensions will be granted (without dean’s excuse). You should
be generating some sphere images without illumination by the end of the
first week to ensure timely completion.
-
Start with image class and writing ppm files. Test with simply created
images like solid color, checkerboard, etc. Make sure you understand your
image coordinate system.
-
Write file parser, and necessary data structures for storing information.
-
Write main loop to generate eye rays for entire image. (As a handy debugging
trick, you can scale/bias your ray direction’s x, y, and z components and
store into r, g, and b of an image. Viewing the image and examining particular
values can help you verify that your eye rays are correct. Storing intermediate
values as colors like this is a often useful way to debug your program's
operation on an entire image at once.)
-
Write sphere intersection routines and use with eye rays. Set image colors
to sphere diffuse color. Don’t do any illumination. Your image should thus
contain solid-colored ellipses indicating which spheres are visible at
each pixel. Run on my test scene and compare images.
-
Add purely local Phong illumination computation.
-
Add shadow rays to determine which lights contribute to each pixel’s illumination.
-
Come up with your own test cases and debug.
-
Design extremely cool demonstration image.
You could choose to postpone the parsing until later in the development,
using hard-coded tests until then. However, if you choose to do it early
on, you can immediately start testing any cases you think might give your
code trouble.
Deliverables
E-mail me a single .zip file (uuencode the file or do mime attachment)
containing the following:
-
well-commented source code (I actually read the comments and code)
-
instructions for compiling (running should work as specified above)
-
one or more interesting scene files and rendered images (with .rt1 and
.ppm extensions)
-
brief description of each scene (this can be comments at the start of the
file)
Please do not invent a new, clever way to turn in the assignment, and do
include all of the above items (I have many assignment to review, so submitting
them in a fairly uniform way makes the process much smoother).
PPM Format (extension .ppm)
PPM format has ASCII and binary variants. I’ll first describe the ASCII
version:
P3
xres yres
255
r g b r g b r g b r g b
r g b r g b r g b r g b
…
P3 is a magic number that identifies the file type. xres and yres
are integers specifying the image resolution. 255 is the maximum color
value. r, g, and b are the color values of the pixels. They are each an
integer in the range [0, 255]. You can place carriage returns wherever
you like in the list of pixel values. Comment lines starting with # are
also allowed in the ASCII format.
The binary format is almost the same, except the magic number is P6
and the rgb values in the file are written out as byte values instead of
ASCII strings (comments, spaces, etc. are not allowed in this portion of
the file).
You should probably start with the ASCII version to test things out,
then convert to the binary version, which occupies several times less space.
Scene Description Format (extension .rt1 – that’s
a number 1)
Numbers in angle brackets are real numbers, in square brackets are integers
Naturally, the brackets do not appear in the actual file (but the colons
do).
Blank lines and white space should be ignored
Lines with a ‘#’ as the first character are comments and should be
ignored.
Colors should be specified in the range [0.0, 1.0]
Angles should be in degrees, and refer to the full angle (as opposed
to the half angle)
# comment lines start with # and may appear anywhere
RESOLUTION: [x resolution] [y resolution]
FIELD_OF_VIEW: <full x field-of-view>
BACKGROUND: <red> <green> <blue>
NUM_LIGHTS: [number of lights]
LIGHT
POSITION: <x> <y> <z>
DIRECTION: <x> <y> <z>
INTENSITY: <red> <green> <blue>
EXPONENT: <exponent>
CUTOFF: <angle>
ENDLIGHT
LIGHT
…
ENDLIGHT
LIGHT
…
ENDLIGHT
…
#in other words, one LIGHT…ENDLIGHT block for each light
NUM_SPHERES: <number of spheres>
#similarly, one SPHERE…ENDSPHERE block for each sphere
SPHERE
CENTER: <x> <y> <z>
RADIUS: <radius>
DIFFUSE_COLOR: <red> <green> <blue>
DIFFUSE_COEFFICIENT: <coefficient>
SPECULAR_COLOR: <red> <green> <blue>
SPECULAR_COEFFICIENT: <coefficient>
SPECULAR_EXPONENT: <exponent>
ENDSPHERE
SPHERE
…
ENDSPHERE
SPHERE
…
ENDSPHERE
…
I have made this format as simple as possible to parse, with little
room for variation except white space and number of lights, spheres, etc.
You can write your parser by hand or use lex/yacc to generate a parser.
If you use lex/yacc, do include the properly-generated .c and .h files
with your program source as well as the original lex and yacc input files.
Final Words of Encouragement
Good luck on your first assignment. I hope that in addition to being a
lot of work, it provides you with some fun and satisfying moments. Remember
that I'm available to answer questions in class, by e-mail, or by appointment.
September 20, 1999