Valid XHTML 1.0!

Homework 4: Shaded renderer in OpenGL

In this assignment you will modify your solution from homework 3 to use OpenGL. You will also make it interactive, so that the user can examine (i.e. rotate, translate, and zoom) the rendered object. The program will also allow the user to choose a shading style (wireframe, flat, Gouraud).

Your code from Homework 0 will help for this lab. Mark Meyers' slides on OpenGL/GLUT should be very helpful, as well as the OpenGL links on the Resources page.

Homework 4 is due on Tuesday Nov. 4 at 11:59 pm

Rendering with OpenGL

From homework 3, you should have a working parser that reads in an ivfile and store relevant data in some internal data structure. Instead of rasterizing polygons by manually computing lighting functions, we want OpenGL to do all the tedious work for us.

Lighting and Shading

In OpenGL, lights have various colors components just as materials do: diffuse, specular, etc. You should set the specular and diffuse colors to the color given for the light in the OpenIV file. Set the ambient color to (0,0,0). See homework 0 for an example of setting up light and material properties.

Transformations

All your matrix transformations are to be handled by OpenGL. OpenGL has three matrix modes -- projection, modelview, and texture. Each mode has a separate matrix stack, and you call glMatrixMode(...) to change the effective stack. You won't be using the texture matrix stack at all, and aside from perspective transform, which goes to the projection matrix stack, everything goes to the modelview matrix stack. OpenGL supports what your 4x4 transform library from homework 1 does: glTranslatef(..), glScalef(..), and glRotatef(..). Use them!

Note that OpenGL functions typically take rotation angles in degrees, so you'll need to convert the values given in the .iv files. Also, make sure the order of the parameters are correct! One common mistake is mixing up the order of angle and axis in glRotatef(..).

Outline of transformations

// perspective and camera are setup only once in the beginning of program
PROJECTION
Frustum

MODELVIEW
camera rotate -theta
camera -translate

for each frame:
  push

  // user mouse translate and rotation -- more details later

  for each object:
    push
    transform(s)
    //draw the polygons
    pop

  pop

Rendering

Drawing primitives (triangles or lines in our case) with OpenGL is very simple. For example, to draw a triangle, we simply feed it the three vertices:

glBegin(GL_TRIANGLES);
glVertex3d(...); glVertex3d(...); glVertex3d(...);
glEnd();

Depending on the flag you use in glBegin(...) , you get different drawing modes.

Your renderer should support multiple rendering modes and should allow the user to switch modes by pressing keys. It should also be able to display a wireframe version of the object (as in homework 2) when the user presses the w key (use glBegin(GL_LINE_LOOP) instead of glBegin(GL_POLYGON)), a flat-shaded version when the user pressed the f key, and a Gouraud-shaded version when the user pressed the g key. To get different shading models, use glShadeModel(...) . Refer to glutKeyboardFunc() docs to get key handling working. Alternatively, simply refer to homework 0 again for an example.

Using OpenGL to do these operations is required.

User Interface

To register mouse motion or mouse click, we must set callback functions much like what we do with the display function and keyboard function. In particular, look at glutMouseFunc() and glutMotionFunc() to get mouse input working.

Translation

When the user clicks and drags using the middle mouse button, the objects should track (move parallel to the image plane). The magnitude of the movement should be proportional to the length of the mouse drag. The direction of the move should be that of the mouse drag.

Zooming

When the user presses shift and drags using the middle mouse button, the camera should zoom (implement this as translation in the -z camera direction). The magnitude of the zoom should be proportional to the vertical displacement of the mouse drag.

Rotation

When the user clicks and drags using the left mouse button, the objects should rotate. There are many ways to do this - you should pick something reasonably intuitive and explain how your rotation works in your README file.

One approach is to make the axis of the rotation perpendicular to the mouse drag line in the image plane (parallel to the image plane and perpendicular to the drag line). The angle of the rotation should be proportional to the length of the mouse drag. The center of rotation should always be 3 units in front of the camera. For any normalized axis of rotation (x, y, z) and angle of rotation (theta), the 3x3 rotation matrix is:
3x3 rotation matrix

Another way to do rotation is by using the
arcball method.

The rotation should be interactive. That is, results should be visible as the user is dragging (not only after the mouse button is released). Never directly call your redisplay callback, however. Instead, simply call glutPostRedisplay() to let GLUT know that it needs to call your redisplay function. This way you get less "lag" while being interactive, since it takes input before waiting for the graphics card.

Note that after setting up the lights in the beginning of the program, there is no need to transform the light locations in any way when the object is dragged. The lights are stationary even as the rest of the scene is transformed.

HINT: Depending on how you implemented your mouse transforms, you may need to: get the current modelview transformation matrix, tell OpenGL to start over at the identity matrix, make your own transformations, and then multiply by the original matrix. Here's how that is done:

    GLfloat oldMatrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, &oldMatrix[0]);
    glLoadIdentity();
    
    // apply mouse transforms here

    glMultMatrixf(&oldMatrix[0]);   

Error handling

You do not need to handle OpenGL errors (presuming your code does not normally cause them!). However, if you'd like to check whether OpenGL errors are occuring, see the sample code here. This may save you a lot of trouble if OpenGL is behaving strangely.

What your program should do

Your program should be able to read in a scene description and produce an interactive rendering of the scene. The syntax for the program should be:

    oglRenderer <xRes> <yRes> < <iv-file>

The xRes and yRes specify the image dimensions, while the iv-file is the scene description. Note that changing the image dimensions may change the appearance of the scene (due to aspect ratios of monitors, etc.). You can control this behavior by changing the viewport size with the callback you specify with glutReshapeFunc().

Include a README file with your code, saying what you did, how to compile it, and anything else you think we need to know.

Extra credit

Feel free to implement a few additional features to your renderer. Points will be awarded based on the difficulty and implementation. You may want to talk to a TA before implementing the additions.

Lineset

This extra credit will be worth 1 point.

Separator {
    Transform {
      translation 0 0 0
      rotation 1 0 0 0
      scaleFactor 1 1 1
    }
    Coordinate3 {
                    point [
                                0 0 0,
                                0 1 2,
                                0 2 3,
                                1 0 0,
                                1 1 3,
                                1 2 2,
                                2 0 1,
                                2 1 3,
                                2 2 2
                          ]
    }

    LineSet {
                    numVertices 9
    }
}

This extra credit feature is easy to implement; ignore the wireframe/flat/gouraud mode and just draw connected lines with glBegin(GL_LINE_STRIP). Of course you have to add the LineSet and numVertices features to your parser, and you have to make sure that you don't depend on the data being in the form of polygons. NOTE: More than one Separator can have a LineSet, so you must still draw all Separators. More than one Lineset per Separator is unnecessary. You should also disable lighting.

Care of The Complete Idiot's Guide to Ivview, we have a really cool OpenIV file of Lorenz's Strange Attractor, a beautiful and simple fractal:

A view of Lorenz' Strange Attractor

A different view:

A different view of Lorenz' Strange Attractor

Some iv files and sample images.