
Don't see the menu?
|

EECS487 F09: PA1
EECS487 F09 PA1: Raster Graphics
The assignment is due on Monday
September 28th, 2009 at 12:01pm (one minute after noon).
Plain Page for Printing
Overview
In this assignment you will implement the midpoint line drawing
algorithm to rasterize line segments, as well as a simple method for
scan converting triangles. You will also use barycentric coordinates to
interpolate colors and provide simple anti-aliasing for lines and
triangles.
You are given support code for this assignment that should compile
under Linux, Windows, and Mac OS X. The support code links against the
png and glut libraries. It also reads an input
scene file, calls helper functions for each primitive (line or triangle),
and brings up an OpenGL window that
shows the rendered image. It can output the resulting image as a
png file as well. The input file format is described below, and a number of
example input test files are provided.
Grading tasks (100 points total)
- Implement the midpoint algorithm for line segments. 15pts
- Implement triangle rasterization. 20pts
- Implement line clipping. 10pts
- Implement color interpolation for line segments. 10pts
- Implement color interpolation for triangles. 10pts
- Implement anti-aliased rendering/filtering for line segments. 10pts
- Implement anti-aliased rendering/filtering for triangles. 10pts
- Implement simple shading model for triangles. 10pts
- Writeup. 5pts
Implementation details
Midpoint algorithm for line segments
Modify Rasterizer::RasterizeLine function to implement
the midpoint line rasterization (see Lecture 3). The lines should be
one pixel wide. At this stage you can
ignore the line colors and render white lines.
Triangle rasterization
Modify Rasterizer::RasterizeTriangle function to
implement the triangle rasterization algorithm (see Lecture 4)
Line clipping
Add functionality for clipping the lines before scan converting
them. The goal is to discard any line segment that lies entirely
outside the window, and trim line segments that lie partially outside
the window, leaving only parts that are inside the window. This can
greatly improve rendering speed for some inputs.
Color interpolation for lines
Take into account vertex colors and implement color interpolation
using the parametric equation of a line segment.
Color interpolation for triangles
Use barycentric coordinates to interpolate vertex colors within the
triangle.
Anti-aliasing
In the anti-aliased mode you will need to first render into a larger
auxilliary image buffer (of size 3*WIDTH by 3*HEIGHT), and then
post-process the resulting image to downsample it to the original image
buffer. This is a simple method sufficient for our purposes. For
downsampling use the box filter (simply average the colors in each 3x3
group of pixels). You can modify Rasterizer::BeginRender
and Rasterizer::EndRender functions to implement these
pre- and post-processing steps.
-
Anti-aliasing for lines
For lines, render a three-pixel thick line into the auxilliary
buffer. You will need to compute new vertex coordinates appropriately.
For horizontal and vertical lines, make sure that the anti-aliased
result is the same as the one without anti-aliasing.
-
Anti-aliasing for triangles
For triangles, simply adjust the vertex positions and render
the triangle into the auxilliary buffer.
Simple shading model
When the lighting is on, you need to perform the following
computation for each vertex: assume that the light is positioned very
far in the direction given by a vector l=(1, 1, 1). Normalize vector
l and each vertex normal n, and compute the dot product dot(l,n).
If the dot product is negative assign the resulting vertex color to be
completely black (it faces away from the light). Otherwise assign the
color to be (R*dot(l,n), G*dot(l,n), B*dot(l,n)) where
(R,G,B) is the input vertex color (that is, the color you use when the lighting is
off). Then use the resulting color when rendering a triangle.
Scene file format
Input files are given in a simple line-based format. Each line
specifies a vertex position, a change in rendering mode, or a change in
current rendering parameters. At the beginning, the current rendering
code is set to default which renders nothing, the current color is
white (1.0, 1.0, 1.0), and the current normal is up (0.0, 0.0, 1.0).
Each line starts with a lower-case character followed by zero or
more numbers, separated by spaces. The starting character specifies a
command. The following commands are defined:
- 'c red_float green_float blue_float':
change the current color to (red_float, green_float, blue_float) where
the numbers are in the range from 0.0 to 1.0.
- 'n x_float y_float z_float': change the
current normal to (x_float, y_float, z_float) which may not be
normalized. You will need to normalize the normal to have unit length
in order to perform lighting calculations.
- 'l': changes the rendering mode to draw individual line segments.
In this mode, each pair of vertices will cause drawing a line segment
between them. Thus, if 2*N vertices are specified then N segments will
be drawn.
- 't': changes the rendering mode to draw individual triangles. In
this mode, each triple of vertices will cause drawing a triangle with
these vertices. Thus, if 3*N vertices are specified then N triangles
will be drawn.
- 'v x_int y_int': specifies a vertex with
coordinates (x_int, y_int). Depending on the rendering mode the vertex
command may cause rendering of a primitive (line segment or a
triangle).
Coordinate systems
The bottom left pixel is at (0, 0), the x-axis goes to the right, and
the y-axis goes upwards (this is the OpenGL convention, note image
files like png usually have the origin at the top-left corner with
y-axis going downwards, the support code handles this during image
writing, so that the image you store should look like what you see in a
glut window).
Support code details
First of all, copy the support code archive from the file /afs/umich.edu/class/eecs487/f09/PAs/pa1.tgz,
which contains the source code, some useful data, and some images.
The executable pa1 should
be called with at least one command-line
argument. The first argument specifies the input file name, and the
second argument (optional) specifies the output png file name. If the
second argument is not specified the image is written to output.png.
The image file is only saved when 's' is pressed in the glut window.
The following keystrokes are defined in the glut window (you may map
more operations to keys inside KeyboardCallback() function
but you should not change the predefined keys below).
- 's': saves the image file
- '1': sets the pixel zoom to 1.0 (default value).
- '2': sets the pixel zoom to 2.0.
- 'a': toggles the anti-aliasing mode on/off, re-reads the input
file, and re-renders the scene. (Anti-aliasing is off by default).
- 'l': toggles the lighting mode on/off, re-reads the input file,
and re-renders the scene. (Lighting is off by default).
- 'c': toggles the clipping mode on/off, re-reads the input file,
and re-renders the scene. (Clipping is on by default).
- 'r': re-reads the input file, and re-renders the scene.
The anti-aliasing, lighting, and clipping modes are stored as boolean
member variables of the Rasterizer class, and changed by pressing the
appropiate keys. You should use these variables in your rasterization
routines to select appropriate modes.
The code needs to be linked against png, zlib, and glut libraries,
and the compilation requires the corresponding header files. The CAEN
Linux setup provides both the libraries and the headers, and no setup
is needed (just run make within the pa1 folder). On Windows, we
provide the headers in common/include folder and the precompiled
libraries in common/lib folder, and Visual Studio project files refer
to those (also see the paragraphs below).
Linux specific:
The following sequence should work: download the assignment archive,
unpack it, and run make on it. Then run the executable with the
appropriate scene file from the data folder. You may try the following
commands that pretty much do these steps:
mkdir eecs487f09
cd eecs487f09
wget
login-linux.umich.edu:/afs/umich.edu/eecs487/f09/PAs/pa1.tgz
tar xvzf pa1.tgz
cd code/pa1
make
./pa1 ../../resources/sample.txt output.png
# -- a window should appear, press 's', and then close it.
eog output.png
This should run the application, show its window,
save an image file, and then use the gnome image viewer, eog to view it. Once
this works you can start modifying rasterizer.cpp to add your
code.
Windows specific:
On CAEN Windows machines, you may need to mount the drive with the
assignment data folder to get a drive letter, and then specify that path
in Project Properties→Configuration Properties→Debugging→Working
Directory (as well as specifying the scene filename as the command
argument). The libpng.lib library should be installed on
CAEN machines already. If you have problem with this, please see Ari.
Mac OS X specific:
Download and install
libpng.lib.
Then follow the steps as for Linux above. To use Xcode, add libpng.lib as an existing file.
See Ari if you have problem with installing libpng.lib or using Xcode.
Sample data
Here is a simple scene file with the
corresponding image output. See some more
examples below.
Note: clipping mode should not affect the image (except perhaps for
some rounding of the segment positions on the boundary) -- it should
however run much faster for specially designed bad examples that have
very long segments off-screen.
Submission Guidelines
Review the grading policy page of the course web site. Remember that
to incorporate publicly available code in your solution is considered
cheating in this course. To pass off the implementation
of an algorithm as that of another is also considered cheating.
For example, if the assignment asks you to implement sort using
heap sort and you turn in a working program that uses insertion
sort in place of the heap sort, it will be considered cheating.
If you can not implement a required algorithm, you must
inform the teaching staff when turning in your assignment, e.g.,
by documenting this in your writeup.
Code that
doesn't compile will be heavily penalized. Make sure your code compiles and works
on CAEN machines.
You will need to turn in your source files
together with appropriate Makefile or IDE project files and a
write-up in text format (writeup-uniqname.txt) that discusses:
- Your platform -
Windows, Linux, or Mac OS X.
- Anything about your implementation that is noteworthy (e.g., your
method for clipping lines, or color interpolation).
- Feedback on the assignment.
- Name your file writeup-uniqname.txt. For example, the person with uniqname
ysoserious would create writeup-ysoserious.txt.
Copy your code, write-up and any other supporting files (Makefile
or IDE project files etc.) to the following directory on IFS /afs/umich.edu/class/eecs487/f09/SUBMIT/<uniqname>/pa1.
This path is accessible from any machine you've logged into using your
ITCS (umich.edu) password. Report problems to ITCS.
For accessing the umich.edu AFS partition from CAEN machines you
might first have to obtain AFS tokens. On Linux, this is performed
using the 'gettokens' command on the terminal, followed by your ITCS
password. On Windows, invoke the Start Menu -> All Programs ->
Communication Tools -> Open AFS -> Authentication which will
create a lock icon in your system tray. Click that to get the AFS
authentication dialog, click "Obtain New Tokens..." and enter your ITCS
uniqname and password for the umich.edu cell.
The timestamp on your source files and your writeup will indicate
the time of submission and if this is past the deadline your submission
will be considered late. Therefore, you are allowed multiple
'submissions' without late-policy implications as long as you respect
the deadline.
Test the compilation!
Your submission must compile without errors and warnings on CAEN
machines. Mention the platform in your writeup.
Turn in ONLY the files you have modified.
Do not turn in support code we provided that you haven't modified.
Do not turn in any binary files (object, executable, or image)
with your assignment.
General
You are allowed and encouraged to discuss various aspects of this
assignment with your classmates. However, the overall design and final
details and implementation must be your own.
Coding style
- Use a reasonable organization for your overall program:
- Design a fairly reasonable class structure. On the one hand,
don't stick everything into one class/struct. On the other hand, don't be
bureaucratic and require the reader to follow one class definition
after another to find a single line of code wrapped in n layers of
methods, with each method doing nothing but calling the next one.
If the way you design your code feels sloppy to you, it
probably is. Utilize multiple files in a way that is consistent with
the general use of C/C++. Don't use more files than necessary, you don't
have to put each class/struct in a separate file of its own.
Don't use literals!
- Use either
const, enum, or #define
to give your literals meaningful names. We do deduct points for each
occurrence of literals, even if it is the same one. The only
exceptions will be for loop counter, command-line options, NULL(0) and
TRUE/FALSE(1/0) testing/setting, and help and error messages printed
out to user.
Use reasonable comments:
- Explain what each class does and what each data member is used
for. A one or two line description of most member functions is also
desirable. Where you use non-standard coding techniques, document them.
List your name and the date last modified for each file.
-
- Remember that a useless comment is worse than no comment at all.
int temp; // declare temp. variable
would be an example of a useless comment which just makes code harder
to read!
Use reasonable formatting:
- From indentation alone, it should be obvious where a given code
block ends. Avoid lines that wrap in an 80 column display wherever
possible. Your code should be tight, compact, and visually tidy. Don't
let bits and pieces fly off every which way. Your code is not abstract
painting.
Variable names:
- Use reasonable and informative variable names, but limit name
size to a reasonable length. A 40-character name better has a very good
reason to exist. Variable names like 'i' and 'j' can be reasonable, but
you should not use such variables to store meaningful long-term data.
Other than LCV (loop control variables) you should use descriptive
names for your variables, functions, classes, methods, structures, etc.
Reduce, Reuse, and Recycle your code, algorithms, and structures:
- Try using inheritance, templating, polymorphism (virtual
function), or similar methods to reduce the size of your code. Do not
unnecessarily duplicate code. Less code leads to less debugging. If you
find yourself rewriting basically the same code more than once, stop
and try to see if you can somehow reuse the code by making it a
function call or implementing a polymorphic function.
Unreadable code can cost you up to
10 points!
Empirical efficiency
We will check for empirical efficiency both by measuring the memory
usage and running time of your code and by reading the code. We will
focus on whether you use unnecessary temporary variables, whether you
copy data when a simply reference to it will do, whether you use an
O(n) algorithm or an O(n^2) algorithm, but not whether you use
printf's or fprintf's. Nor whether your ADTs
have the cleanest interfaces. In general, if the tradeoff is between
illegible and fast code vs. pleasant to read code that is unnoticeably
less efficient, we will prefer the latter. (Of course pleasant to read
code that is also efficient would be best.) However, take heed what you
put in your code. You should be able to account for every class, method,
function, statement, down to every character you put in your code.
Why is it there? Is it necessary to be there? Can you do without?
Perfection is reached not when there is nothing more to add, but when
there is nothing more that can be taken away, someone once said.
Okay, that may be a bit extreme, but do try to mind how you express
yourself in code.
Hints and advice
Testing Your Code
We will be grading for correctness primarily by running your program on
a number of test cases.
If you have a single silly bug that causes most of the test cases to
fail, you will get a very low score on that part of the programming
assignment even though you completed 95% of the work.
Most of your grade will come from correctness testing.
Therefore, it is imperative that you test your code thoroughly.
Each testcase should test only one particular feature of your
program.
If any part of this document is unclear, ambiguous,
contradictory, or just plain wrong, please post your questions
on the course forum. Have fun coding!
|