EECS487 F09 PA1: Raster Graphics

The assignment is due on Monday September 28th, 2009 at 12:01pm (one minute after noon).

This page is for printing only, all the links below are broken

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)

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.

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:

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

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:

  1. Your platform - Windows, Linux, or Mac OS X.
  2. Anything about your implementation that is noteworthy (e.g., your method for clipping lines, or color interpolation).
  3. Feedback on the assignment.
  4. 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!