CS 428 - Fall 2011
Project 2: Polygon Meshes and Shading

Due electronically: Wednesday, October 26, 12 noon


Check this page frequently for updates and clarifications
(Significant changes or clarifications are marked with [Update])


Description

In computer graphics, surfaces are often represented with collections of polygons. There is additional structure as well; while the vertices of the mesh represent the geometry of the surface, polygon faces share vertices, so they not only describe where the surface is among the vertices, but also its connectivity.

Because of the broad support of polygon rendering in graphics hardware, polygon meshes are widely used in games and visualization applications. Recent trends in programmable hardware push this even further, with standards like GLSL.

Objective

This project will help you understand how to represent, create, manipulate, and render polygon meshes (in OpenGL and GLSL) in a variety of styles.

Program

You will be provided with skeleton code for this program, which supplies the necessary user interface and main program structure. A simple polygon mesh data structure is provided, along with some code in GLSL. Code which reads a polygon mesh from a file is also provided. You will be filling in the missing parts in functions (which are marked with "// ..."), and are listed in the README.txt file. You must develop the code for computing normals of the polygon mesh, drawing the mesh in various styles, and evaluating tessellated objects (an ellipsoid), in both OpenGL and GLSL.

The skeleton code for this project can be found (on the cereal machines) in the directory
      ~decarlo/428/proj2
Also included is a Makefile and a README.txt file describing the code structure and how to compile and run the program.

There are some example polygon mesh files in:
      ~decarlo/428/obj/
Some of these files are big, so watch your quota (use quota -v). You should probably just make a symbolic link to the objects directory contained inside your code directory, after you copy the code:
    cp -r ~decarlo/428/proj2 .
Make the link like this:
    ln -s ~decarlo/428/obj proj2/obj
In addition to saving your disk space, should more objects be added into that directory, you won't miss them.

GLSL

GLSL is a lot like C (well, the types are a little stronger). We'll be using just the basic features, so don't worry. The GLSL programs you'll be editing are in files that end in .vp for the vertex programs, and .fp for the fragment programs. Refer to the following GLSL materials:

You don't have to compile the program youself; it gets compiled at run-time, and only when you use it. (The main program is designed to work fine on a machine that doesn't support GLSL, as long as you don't turn it on.) The compile-time error messages are helpful for things like syntax errors, type-checking failures, etc... Run-time errors are more problematic, as the entire program aborts. It's a good idea to make small changes to these programs, and then test them, until you feel comfortable with GLSL.

One kind of run-time error you might encounter (that causes the program to exit) happens if your GLSL program is too long. Lengths vary by machine. Make sure your code isn't drawn out -- keep it compact. You don't need to overdo it; in our own development of this project, we didn't encounter this problem. We will be grading the programs in Hill 248 (since those machines are the newest). Note that the machines in Hill 252 are a bit older, and only permit relatively short GLSL programs.

Mathematical functions are available, and are named the same as in C (and on the whole, Java). For instance, sin(), cos(), and pow(). There is also a max() function---if you put 0 as one of the arguments instead of 0.0, that you'll get a type error. These work with float type variables. There are also vector types vec3 and vec4 for three and four dimensional vectors. These have the expected operations: normalize() for vector normalization, dot() for dot product, etc...

Handing in

Hand in the following:

  1. all of your java and GLSL files (no class files please)
  2. your makefile
  3. a description file descrip.txt
The description file should be a very brief description of what you changed and added. Put your name at the top of this file. It should briefly describe all modifications to the skeleton code you performed, as well as describe the additional code you wrote for the assignment. If you implemented any additional/optional features or anything else special, you must state what you did in this file (to get credit).

You will need to create a tar archive to hand in, that contains your java and GLSL files and description:

   tar cf proj2.tar Makefile *.java *.vp *.fp descrip.txt
Here are the instructions on how to hand in this file.

This assignment is a bit vague so that you can make a lot of the design decisions yourself. There are several approaches to the problems here. Use your best judgement to try and get the most useful result. Ask for help or clarification when you need it.

Program use

To run the program, you either read in a polygon mesh from a file, or create one by tessellation. The files are in Wavefront OBJ format (a simplified version, actually, which only reads in the specification of vertex locations and polygon faces -- but you should still be able to use any other OBJ files you might find).

To read in a mesh from a file (for the file "cube.obj" in the objects directory):
    java Mesh obj/cube.obj

To create an ellipsoid (from a 20x30 grid):
    java Mesh -ellipsoid 20 30

To create an ellipsoid (using the default 24x24 grid):
    java Mesh -ellipsoid

Once the program is running, you can transform the object, as well as specify how you want the object rendered (polygons, wireframe, silhouettes, smooth or faceted shading, material properties, etc...) using sliders and checkboxes.

Data structure

All shapes are represented using the Shape class, which contains the parameters for the shape, as well as the mesh used to represent it.

The polygon mesh contained in the Shape is represented as an array vertices, and an array polygons. It is assumed that all polygons are stored in a counter-clockwise fashion (normal vectors point outward), and that their normal vectors are normalized (unit length). The class PolyMesh which extends Shape is for arbitrary meshes (which are read from files). And the class UVShape extends the Shape class to represent a uv-parameterized shape (like an ellipsoid). The Vertex interface (a purely abstract class) represents information about a specific vertex: its location is accessed using getPoint() and its normal vector (averaged from neighboring polygons) is accessed using getNormal(). The Polygon interface represents information about a specific polygon in the mesh. A particular Vertex is accessed using getVertex(), the total number of vertices using size(), and the averaged normal vector using getNormal(). The Polygon interface is implemented by PolygonAccess which just handles the array of vertices in each polygon. The Vertex and Polygon classes are implemented differently by PolyMesh and UVShape. On the whole, the details of these aren't important until you start with GLSL, in which case, you should look how getPoint() and getNormal() work for the UVShape.

All access to the vertices and polygons stored in the Shape class should be through the Vertex and Polygon interfaces. Perhaps you can convince yourself of this by looking at the code for the methods in these interfaces. The vertices stored in each polygon are accessible through Polygon.getVertex(). This returns the actual Vertex object (not a copy of it). It doesn't return an integer index into the array of vertices -- although it could have worked that way, too.

Drawing

The polygon mesh is transformed using an object transformation (like in Project 1, although the order of rotations is reversed here, to make it more intuitive to manipulate objects like the ellipsoid, which are aligned with the Z axis). This part of the code is already written for you. After this transformation, you draw the mesh in Shape.draw. You will be drawing the polygon mesh using one of several styles (perhaps more than one at a time). The following are the styles:

Each of these drawing styles is individually specified through the user interface and are defined as BooleanParameters in Shape.

Normal vectors

Given a polygon mesh, we must compute both the polygon normals (those returned by Polygon.getNormal()), and the vertex normals (those returned by Vertex.getNormal()), which are averaged from the adjoining polygon normals, weighted by area. The code for computing the polygon normals for a is provided for you: see PolyMesh.PolygonPM.computeNormal(). Is uses Newell's method (which is equivalent to adding up normal vectors at the corners), but does not normalize the normal vectors---the length of the vector is proportional to the area of the polygon. You'll need this when computing the vertex normals. For a UVShape, all normals are computed analytically; more on this below.

You must write the code that computes the vertex normals in PolyMesh.computeAllNormals(). This computation is performed on the entire mesh at once (using the algorithm described in class), so that the normal at a vertex is the area-weighted average of the polygon normals over all polygons in which it is contained.

Tessellation

To form the mesh of a parametric shape, you start from a grid of vertices over a 2D domain, and compute its geometry (both points and normal vectors) from analytic equations. So for each point (u,v) in the domain, we can compute its corresponding point on the surface using a function p(u,v) and its (unnormalized) normal vector using n(u,v). For instance, one possible parameterization of an ellipsoid (with three parameters: ax, ay and az - the axis lengths of the ellipsoid in the x, y, and z directions) has the equation:

Here, u is like longitude, and v is like latitude. The grid of points in this domain is already constructed for you---see UVShape.buildUVGrid(). It creates a grid which includes the grid points at u=2&pi as well. But since we are computing normal vectors analytically, this isn't a problem. You must do the following:

Extensions

The following is a list of optional extensions; difficulties are marked.

Hints

The following are some suggestions...


428 Home