Programming assignment 3 - .obj File Loader/viewer/modeler
CS 354 - Introduction to Computer Graphics
Spring, 2015
Don Fussell
DUE Monday March 9 at 11:59pm
In this assignment, you'll expand on your work in Assignment 2 to
become more familiar with OpenGL and scene descriptions by creating
your own 3D model viewer. Your system will read input files in
.obj format, build scene graphs using them, and render the
results. You''ll implement much more sophisticated camera control than
in the previous assignment, and your scene graph will support simple
animations. Here are some objects that you
should be able to parse and display along with code for parsing them.
You may also be able to parse and render other objects in this format
that you find on the web, but at a minimum you must be able to handle
the ones we're giving you.
.obj files contain a rather simple ASCII format that's very
easy to parse. Design your user interface to allow interactively
selecting files to be read into your scene.
Object loader
Each line of an .obj file contains a
record of some sort. The first character of the line indicates what
the type of record is, and thus what to do with the rest of the
line. The only ones you need to implement are:
- # (any text): Comments. Ignore the rest of the line.
- v x y z: Vertex data. The x y z values are the
vertex's position in 3D. Each vertex is implicitly numbered as it's
added, starting from 1.
- f n0 n1 n2...: Face data. The n values indicate which
vertices to connect together to form the face. Each n is an index
into the list of vertices read in so far. There can be an arbitrary
number of vertices that make up a face; there are usually just 3
(triangles), but there's no guarantee. If you encounter a face that
has more than 3 vertices, split it into multiple triangles as if it
were a triangle fan.
There are several other record types that you'll encounter, but you're
free to ignore them. Once you've loaded the model, compute normals
for both faces and vertices. Assume counter-clockwise winding for the
face normals, then average the incident face normals to produce
normals for each vertex. Note that the parser in loader.h
assumes a Trimesh object with methods for adding vertices and faces is
provided in geom.h (not provided). Such an object maintains a
list of vertex positions and defines the face mesh using indices into
this vertex list. Designing this will be one significant part of this
assignment. You are free to modify loader.h as you see fit
to accomplish the project.
Camera control
Being able to move the camera around is crucial when trying to examine
an object, so the second part of this assignment is to add orbit-style
camera control. In this type of camera control, there's a point of
interest that the camera is looking at. The camera can orbit around
the point, zoom in and out, and move the point around by panning.
Implement these controls with the following mouse operations:
- Left click & drag: Orbit around the point of interest.
- Middle click & drag: Pan the object (move the point of interest
in the camera's X/Y plane).
- Right click & drag: Zoom in/out on the point of interest.
Make sure that you set the camera controls to sensible defaults when
starting up! The initial point of interest should be the center of the
object, and the zoom level should comfortably fit the object in the
window. Your camera must do perspective projection, not orthonormal
projection. As before, you're free to use the built-in OpenGL
transformation and perspective functions to implement your camera; you
don't need to do any of the matrix math yourself. You are also
allowed to use gluLookat as before if you choose.
Rendering
In addition to the camera, you will also implement several rendering
modes. The best way to expose these to the user is probably as
keyboard commands, but it's up to you to determine how the user
interface works.
Implement the following list of rendering options:
- Point mode: Just draw the vertices.
- Wireframe mode: Draw the edges of the mesh.
- Solid mode: Draw filled triangles.
- Shaded mode: Basic lighting, see below.
- Face normals: Add a toggle to display the face normals.
- Vertex normals: Add a toggle for the vertex normals as well.
As you'll see, solid mode is not very useful; all it displays is a
solid block of pixels in the outline of the object. To make the
display a little more sensible, you'll implement a shaded mode as
well. For shaded mode, you can use OpenGL's default
lighting. The following code snippet shows you how to do this:
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
// draw triangles here
// use glNormal3f() to submit a vertex normal with each vertex
glDisable(GL_LIGHTING);
Hierachical modeling and motion control
You should implement all camera and object motions as well as
placement of lights using a scene graph. All drawing should be done by
a generic traversal of the graph to draw it. Changes to what is drawn
are accomplished by changes to the scene graph.
You should have several types of scene graph nodes:
- Object nodes: These are nodes that represent a coordinate
frame in your graph. If you want to build a world that consists of
two object, for example, you can make a world object node, link
object nodes for each of the two objects, and each of these in
turn will link to geometry nodes for the geometry in its object.
- Geometry nodes: This is a container for the object descriptions
parsed from the .obj files. You must always have an object
node defined to link to a geometry node, i.e. geometry nodes are
just ways to put actual geometry into an object node.
These will always be leaves in your overall scene graph.
- Transformation nodes: These nodes define transformations
between object nodes. Transformation nodes can link to/from both
object nodes and other transformation nodes.
- Light nodes: These nodes can be linked into the scene graph via
transformation nodes just like object nodes, but they won't serve as
parent nodes to other nodes in the graph. A light node represents
an OpenGL point or directional light and can be positioned using
transform nodes.
- Camera nodes: These nodes contain parameters for the OpenGL
projection matrix for a camera in an eye space local to the camera
node. It also contains parameters for the viewport on the screen
that the camera's view should appear on. Like light nodes, these
are positioned and linked into the graph using transformation nodes,
and no children are linked to them. For simplicity, we will not
require that your project work with multiple cameras at once,
although you are free to implement that capability.
- Motions: To implement motions in your scene graph, you'll want
to update selected transformation nodes every frame. You should be
able to specify interactively a rotation amount per frame and a
translation amount per frame. You may restrict things so that at most
one of these can be specified for a particular transformation node if
you like. This will make the ordering of operations totally
controllable using the scene graph structure.
For simplicity and due to the limitations of the glut GUI
capabilities, you may hard code a scene graph structure to start
with. This scene graph should have a root object, at least one light
node, a camera node and a child object of the root that will link to
the geometry node that contains your parsed object data. All of these
object, light, and camera nodes will be linked by transform nodes.
You should move the camera by manipulating the transform node
connecting it to the world, likewise you will do object motions this
way. Due to GUI limitations, the only required motion is for your
object to be able to spin around any of its local object coordinate
system primary axes. You should be able to turn on or off any
combination of these spins interactively.
Extra credit
As you will presumably notice doing it, there are many ways to enhance
this project if you're so inclined. Here are some suggestions:
- Enhance your system to allow more than one object to be put into
the scene graph. In fact, allow interactive creation and editing of
scene graph nodes to get more general motions as well.
- Lighting control: Add user-editable lights to the scene, which
affect shaded mode rendering.
- Material files: One of the optional parameters in an .obj file is
a material file, which contains color and lighting information for
the materials used in the mesh. You could read out that information
and feed it to OpenGL's lighting system to see the object as
designed.
- Other camera controls: Orbit cameras are great for looking at an
object, but you are probably familiar with various other first and
third person camera control systems from games. Feel free to try
some of these.
- Camera inertia: Some users find it more natural if the camera
keeps rotating around an object after they've released the mouse, as
if they had spun a globe. If you implement such functionality, make
sure to slow down the rotation gradually over time, so the object
eventually stops spinning.
Notes:
- You should use your project 2 code as your starter code, along
with the parser code in the handout. You need not keep the Menger
Cube around.
- As usual, you'll turn this in using Canvas. Also as usual, you
can develop your application on whatever operating system you like,
but before you submit it, you must make sure that it builds and runs
properly on the department Linux machines! All grading will take
place on these machines, so if your code doesn't work on them,
you're in trouble.
Make sure that all the necessary code is submitted, as projects that
don’t build are worth nothing! Make sure you have included your
name and UTCS ID in a comment at the top of each of your
files. Also, include a readme explaining the usage of your program,
including any menu options or keyboard commands. If you use any slip
days, be sure to put that in your readme and email the TA as well.
To get a grade on this project, you’ll need to sign up for demo
session with the TA after you’ve submitted your code. This is when
you’ll run through all the functionality in your project, and the TA
will be able to verify that everything is working as it should. This
is also your chance to show off your extra features and slick
interface!
Last modified: 02/19/15
by Don Fussell
fussell@cs.utexas.edu