The Assignment

For this assignment, you will be modifying the provided sample OpenGL application to model an asteroid or rocky planet. The asteroid 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). Normalize the new vertex position to put it on the surface of a sphere (c), then scale by an fBm noise to create the surface of the planet (d). Repeat this process to produce a more detailed planet model (e).

planetary subdivision

Provided Code

To get you started, a simple OpenGL application has been committed to the GLapp directory in your git repository. This application renders two objects: a textured plane with a sphere floating over it. It uses three external libraries that should work on Windows, Mac, and Linux: GLFW provides window creation and input handling; GLEW manages the OpenGL functions and extensions; and GLM provides vector and matrix types and functions (you do not need to create your own this time).

For Windows, I have precompiled all three libraries into a zip file, together with a batch script that will set the environment variables necessary for CMake to be able to find them. To use these on Windows, you must 1) download the GLlibs.zip file, 2) extract the contents, 3) run the envset.bat script, and 4) restart CMake before you can use CMake to generate the GLapp.sln file. The GLlibs files do not need to be copied into your git repository (and should not be!). It is fine to leave the GLlibs files in your Downloads folder, desktop, or wherever else is convenient. If you move them, you should re-run the envset.bat script in the new location, then re-run CMake to update your visual studio solution file.

For Linux, you should be able to find all three packages in the package manager for your Linux distribution. If CMake does not find any of the three packages, you can set the GLEWDIR, GLFW_LOCATION, and/or GLM_DIR environment variables before running CMake to help it know where to look.

On Mac, I recommend installing them with the homebrew package manager. The provided CMake files will look in the standard homebrew installation location.

You will need a computer capable of running an interactive application with at least OpenGL 3.1. If yours will not work, we have a limited number Windows PCs in the GAIM lab (ENG 005) that you can use.

Octahedral mapping

One effective way to procedurally keep track of the vertex locations and connectivity of an octahedron without using a more advanced data structure is to unfold the octahedron into a regular 2D array:

octahedral unwrapping

You can map the texture coordinate position on the square (u,v in 0..1) to a 3D position (x,y,z) on the octahedron as follows:

float x = u*2-1, y = v*2-1;     // position in square scaled to -1..1
float z = 1 - abs(x) - abs(y);  // z computed to make a pyramid
x += sign(x)*min(0,z);          // flip bottom of pyramid to make octahedron
y += sign(y)*min(0,z);

If necessary, you can also go from a 3D (x,y,z) location to a (u,v) texture coordinate as follows:

float s = 0.5/(abs(x) + abs(y) + abs(z));
float u = (x - sign(x)*min(0,z))*s + 0.5;
float v = (y - sign(y)*min(0,z))*s + 0.5;

App Changes

Remove the provided Plane and Sphere object examples and make your own new asteroid class, derived from Object.

Use the provided Noise1() function to construct your fBm noise based on the 3D vertex positions. You will need to choose an overall scale for the noise input that is scaled to the asteroid size, and stop adding octaves of Noise1 to your fBm noise when the scale becomes too small to matter.

Modify the keyboard code in GLapp.cpp to add levels of subdivision when the user presses '+' or '=' (which are on the same key). Reduce the level of subdivision when they press '-' (or '_').

Use texture coordinates based on the position in the 2D octahedral map. Several vertices around the edges of the square will have the same positions and normals, but different texture coordinates.

Compute the normal at each vertex as average of the individual triangle normals around it, weighed by triangle area. You can compute the area-weighted triangle normal using the cross product of two edges. Accumulate those area-weighted normals at each vertex of the triangle, then normalize the vertex normals once you are done. For this to work, you will need to make sure when you construct your triangles that you are consistent about the vertex ordering (e.g. always counterclockwise). Also be careful to average normals across the seams.

634 only

Instead of using the fBm sum of noise functions, use a spherical variation of the iterated replacement algorithm. At each level of subdivision, rather than normalize the vertex location to put it on the surface of a sphere, place it at a radius half-way between the radii of the other two vertices on the edge, plus a random displacement proportional to the length of the edge. The first set of new vertices will get the greatest displacement, the next set will get approximately half that, etc. Recursively applying this procedure will give you a lumpy planet or asteroid with approximately the same spectral characteristics as the noise version.

Extra Credit

For up to 15 points of extra credit, use a half-edge data structure.

10 points of the extra credit are for creating and effectively using this data structure. You could satisfy these by creating the data structure after the vertex and face arrays have been built and using it to compute the vertex normals.instead of mapping the octahedron into an array, use a half-edge data structure in your subdivision and normal computation.

For full-credit in the extra credit, you must use the half-edge data structure for constructing new asteroid levels as well. One key to managing mesh edits with a half-edge data structure is to perform localized changes. If you try to do the subdivision all at once, the data structure changes rapidly stack up. Instead, you can first split all of the edges, adding an extra vertex to each and turning each triangle into a hexagonal face. Each split is a localized change adding one vertex, two new half edges, and re-establishing the data structure links in all of the affected half-edges. Then you can convert each hexagonal face into four triangles. This is also localized, since it does not require any changes to propagate to the adjacent faces until you are ready for them.

What to turn in

Do your development in the GLapp directory so we can find it. Also include an assn3.txt file at the top level of your repository telling us about your assignment. Tell us what works, and what does not. Also tell us what (if any) help you received from books, web sites, or people other than the instructor and TA.

Turn in this assignment electronically by pushing your source code to your class git repository by 11:59 PM on the day of the deadline and tagging the commit assn3. See the assn0 project description if you accidentally tag the wrong commit and need to retag.

You must make multiple commits along the way with useful checkin messages. We will be looking at your development process, so a complete and perfectly working assignment submitted in a single checkin one minute before the deadline will NOT get full credit. Individual checkins of complete files one at a time will not count as incremental commits. Do be sure to check in all of your source code, but no build files, log files, generated images, zip files, libraries, or other non-code content.