CMSC 435/634: Introduction to Computer Graphics

Assignment 2

Modeling

Due September 27, 2006

The Assignment

For this assignment, you will write a C or C++ program using OpenGL to model an asteroid, "dwarf planet" or planet. The planet will be constructed by recursive subdivision starting from an octahedron (a). At each level of subdivision, each existing triangle should be divided into four new triangles, introducing a new vertex along each edge (b). You should first normalize the new vertex locations to lie at a radius half-way between the radii of the other two vertices on the edge (c). Without the next step, this will give you a finer and finer sphere as you continue the subdivision, but to develop your planetary surface, you will further displace the new vertex position radially in or out by a random amount determined by the level of subdivision (d). The first set of new vertices will get the greatest displacement, the next set will get half that, then 1/4, 1/8, .... Recursively applying this procedure will give you your lumpy planet or asteroid.

The planet should be lit by a single directional light source (the sun). For the lighting to work, you will need to compute a surface normal for each vertex. Compute this normal using an average of the normals for all of the triangles that share that vertex, weighted by the triangle area. Since the vector computed by the cross product has a length equal to twice the triangle area, you can weight by triangle area by summing the un-normalized face cross products. Note that vertices from previous levels of subdivision will not move, but their normals will change at each level.

634 students (only): Also color your planetary features according to altitude and latitude to make an Earth-like planet. Vertices below sea level should be set to sea level, and any triangle entirely at sea level should be colored solid blue. This will mean you will need to use different colors for the same vertex depending on whether you are using it in an above sea-level triangle or water triangle.

Nuts and bolts

A sample "octahedron" program has been provided in your Assn2 CVS directory to get you started. You may need to do a 'cvs update' to get these new files. You can spin an octahedron around with the mouse and switch between smooth and faceted normals with the 'n' key and between solid and per-vertex colors with the 'c' key.

You need not keep these 'n' and 'c' key features, since you only need smooth per-vertex normals, and you only need to do solid color (for 435) or per-vertex color (for 634). They are provided as an example of how to handle key presses. You should support the following keys: 't' to increase the level of subdivision (quadrupling the number of triangles) and 'T' to decrease the level (quartering the number of triangles); 'd' to increase the amount of random displacement and 'D' to decrease it; 'r' or 'R' to select a new random seed (otherwise re-seed your random number generator each time you regenerate your planet); and finally, for 634 students, 's' to increase sea level and 'S' to decrease it.

The octahedron in this program uses hard-coded positions and normals. You will need to choose appropriate dynamic data structures to store the computed vertex positions and normals (and colors for 634 students), and to draw all of the triangles. Only recompute the vertex positions and normals in response to a keypress that changes the planet. When just viewing the planet, you should just be drawing from your precomputed data.

The way GLUT's callback functions work (the ones passed to GLUT through the glut*Func calls) has two important implications for your program. First, the only way to pass data into or between these functions is using global variables. Second, if you use C++, any callback functions must be declared extern "C". For example,

// declare
extern "C" void draw();
// define
extern "C" void draw {
  // arbitrary C++ code
}

Strategy

Think first. The most important decision is what data structures to use to store your geometry. What kind of access patterns will your data structures need to support? Which need to be fast, and which could be slower? Once you've made that decision, incremental development is once again probably your best choice. You could try implementing just the octahedron (without subdivision) using your data structures rather than hard-coded positions. Then you could add subdivision and the first normalization step to make a sphere. Finally, you could add the random displacement to make your planet.

I made the background of the sample program blue since problems with lighting will often lead to totally black triangles, which do not show well against a black background. If you do want to have the black background of space, wait until the end to change it. You may find it useful to add additional keys to change the way aspects of your scene are rendered for debugging — say to turn lighting on and off, color triangles random solid colors to more easily see the triangle subdivision, or use a rescaled normal as color to see if the normals are consistent and smooth. If these don't interfere with the required keys, you can leave them in.

Getting started and submitting your work

You will be using the university linux.gl systems, and using CVS to submit all work in this course. Refer to the class CVS instructions for details, but you will need to first check out a copy of your CVS files from the class repository. This will give you the sample files you need to start work on this assignment. Do all of your work in your checked out copy, then check in your submission by the deadline. DO NOT work directly in the repository, if you do, we may not be able to retrieve your assignment and your work may be lost!

Turn in this assignment electronically by checking it into your Assn2 CVS directory by 11:59 PM on the day of the deadline. We will use a dated checkout for grading, so you will be graded on whatever has been checked in as of 11:59 PM. Submit a readme.txt file telling us about your assignment. What help, if any, did you receive from books, web sites or people other than the instructor and TA?

Also submit all source and data files we need to build and run your submission. We should be able to run 'make' in your submission directory on the linux.gl systems to produce your interactive program executable, which should run with no command line arguments. Submit your modified Makefile, any C/C++ files, and any other auxiliary files we might need, but not the object (.o) or executable files. Be sure to comment your code! You will not be graded on the presence or quality of your comments, but we will look at your code. Anything that helps us understand what you did (or were trying to do) can only help. In any case, your programs are expected to be robust and easy to understand.

Remember: If you do not include the statement of help in a readme submitted with your assignment, the assignment will be returned ungraded!!! You will need follow the CVS instructions to cvs add this file for it to be included it in your submission. Since this is the first assignment, you may want to check out a second copy of your repository after you submit to make sure your submission is complete.

Working at home

If possible, don't. We test things out on the university computers and may or may not be able to help you if things don't work right for you at home. However, OpenGL and GLUT are both available on almost every platform out there: Linux, Windows, Mac, Irix, Solaris, HPUX, ... If you are comfortable in finding and installing either of these without help if they are not already present on your system, and in figuring out how to adjust the provided Makefiles for your build environment, it is possible to develop elsewhere. If you do work at home, your final submitted version must be able to build and run on the gl machines and must be electronically submitted there. Avoid non-portable external libraries and functions and pay particular attention to your choice of random function. drand48() is a good source of random numbers between 0 and 1, but if you develop on Windows, you'll need to use something like rand()/(double)RAND_MAX instead.