Department of Computer Science
Worcester Polytechnic Institute

CS-4731: Computer Graphics
Assignment 3
Due: November 28, 2006 at 11:59pm

Objective: In this assignment, you will learn how OpenGL maintains the current states of the Modelview and Projection matrices. To do this, you will replace all OpenGL calls that affect changes to these matrices with your own versions. In the end, the only real OpenGL calls you will have left in your program are those to load your resultant matrices into the actual ones OpenGL will use to render. As in previous assignments, this assignment consists of two parts: a "Preparation" part and a "New Stuff" part.

Background: For this project, you are provided miniGL, an object-oriented C++ wrapper for OpenGL. Using miniGL, you can either choose to simply run pure OpenGL commands, or run your own homegrown OpenGL functions. For instance, typing ./cs4731 -openGL -bounce runs the miniGL bounce example using pure OpenGL, but typing ./cs4731 -cs4731GL -bounce will run the miniGL bounce example using your implementation of the OpenGL calls. With -openGL, the miniGL function mgl.mglRotated is simply a call to glRotated and mgl.mglTranslated simply calls glTranslated. With -cs4731GL, the miniGL function mgl.mglRotated calls your implementation of rotation and mgl.mglTranslated simply calls your implementation of translation.

Preparation: Get and compile the code base miniGL which is provided in tar format for unix. The README file may be useful in knowing how things are written and getting things going. Makefiles for the Unix and Mac OSX environments have been included in the miniGL tar file. You can use these to create a makefile for MinGW, or work on CCC (though this will be slow). Simply compile the miniGL code base and try to run it. Look in the README file for what options are available and run the codebase. In addition to the examples listed, the -house application also runs the house example from Chapter 5 of Hill.

New Stuff:

In this project, we are trying to explore implementations of portions of the graphics pipeline in the absence of OpenGL. You will be required to use the -cs4731GL option instead of -openGL, which should call your own function implementations. Specifically, you should edit the file cs4731GL.cpp and replace all calls that modify the Modelview and Projection matrices with your own code. The current version just calls the corresponding OpenGL function. Your task is to replace these calls with your own code, and remove the OpenGL calls. All of the calls you will need to implement have been grouped at the bottom of the file cs4731GL.cpp. In addition, you will have to define and maintain your own data structures for maintaining, pushing, and popping the current versions of the Modelview and Projection matrices.

As an implementation note, your implemented commands should have the same "feel" to the user as if they were making OpenGL calls. So, for example, if the programmer uses mgl.mglTranslated in his/her program, it should have the same exact behavior whether his/her program is run using the -openGL switch (pure OpenGL glTranslated) or the -cs4731GL option. The examples provided should not exhibit dislocations or any different behavior when your implementation is invoked.

MiniGL comes with examples (listed in the README file) which are ready to run, as well as the house with a jack example from Chapter 5 of Hill. You are not required to do any more modeling. You shall simply write the required OpenGL functions (see below). To keep the project to a manageable size, we will implement only a portion of the pipeline. Specifically, we will implement only commands for selecting matrix modes (e.g. glMatrixMode) or changing the modelview or projection matrices. Thus, while you will implement your versions of some commands, some commands will continue to be handled using pure OpenGL implementations.

The specific goal of this homework is to work with matrices. You are going to build and maintain your own MODELVIEW_MATRIX and PROJECTION_MATRIX matrix stacks. You will set OpenGL's actual MODELVIEW_MATRIX or PROJECTION_MATRIX whenever your MODELVIEW_MATRIX or PROJECTION_MATRIX changes. The actual transform and rendering operations in OpenGL should work as they did previously since all you are doing is building and maintaining two of OpenGL's matrix stacks. In cs4731GL::mglTranslated, you should build the necessary translation matrix and update your MODELVIEW_MATRIX. Before exitting your cs4731GL::mglTranslated function, you should then update the actual OpenGL MODELVIEW matrix by calling glLoadMatrixf. See glLoadMatrix reference for more details on using glLoadMatrix.

Note that when you create a 3D model (e.g., glutWireCube), its vertices are simply sent through the OpenGL pipeline. In this homework, we will continue to do this. However, we will replace the matrices that OpenGL maintains for us with the ones we have maintained, so that the vertices are sent through our versions of the MODELVIEW_MATRIX and PROJECTION_MATRIX.

You should use the Matrix.cpp and Matrix.h files. You will need to augment and/or change the provided matrix class to construct arbitrary scale, rotate and translate matrices (the translate is provided as an example).

Note that the sdl.cpp and sdl.h files I gave you already contain some matrix manipulation utilities. You may not use these utilities. You can look at the code for the affine stack which may give you some ideas on how to write your own.

Specific Requirements:

  • Most of the changes you will make will take place in the files cs4731GL.cpp and Matrix.cpp.
  • Reimplement mglTranslated (and f), mglRotated(f), mglScaled(f) methods which modify the MODELVIEW_MATRIX stack.
  • Reimplement mglMatrixMode which selects either the MODELVIEW_MATRIX or the PROJECTION_MATRIX and the mglPushMatrix, mglPopMatrix, and mglLoadIdentity methods to complete the MODELVIEW_MATRIX stack.
  • You will need to augment the provided matrix class to construct orthographic and perspective transformations. These will replace the remaining pipeline projection calls related to matrices that have been previously done by OpenGL. You will need to handle any mglFrustrum, mgluLookAt, and mglOrtho calls used in the examples provided. Once the basic infrastructure is in place, the difference between mglFrustrum and mglOrtho is negligible (simply using a different matrix).
  • Everytime you handle any commands (e.g., mglTranslated, mglRotated, etc.) which change your modelview or projection matrices, you should update the actual OpenGL modelview or projection matrix. You simply use the glLoadMatrixf function to update the actual OpenGL matrix whenever your version of the matrices change.
  • Once your methods are working, remove all of the OpenGL calls you have replaced. Do not comment them out or ifdef them out. Completely delete them from the file. This reduces confusion during grading. In fact, when you submit your code, the only pure OpenGL commands allowed in your command implementations are commands to load (update) the OpenGL matrices.

Some hints:

  • You may need to record and check which matrix mode you are in for each operation!
  • You can determine if your matrices are correct by using the glGet routines to get matrix values constructed by OpenGL. The values should be approximately the same as yours. Once you have check make sure you remove the OpenGL calls.
  • You can plug in known values for the matrix operations and test that your matrix operations and multiplications work. For instance, one simple debug strategy may be to call both your cs4731GL::mglTranslated and the pure glTranslated, then print and compare both values.
  • A very good reference for what each of these functions actually does can be found here.

Extra Credit: The extra credit for this assignment provides more-flexible camera control.

Flexible Camera Control: For the commmand ./cs4731 -cs4731GL -house, allow the user to move the camera to view your scene from various points. To do this, in the file hill_house.cpp, edit the functions key and special to update the camera parameters.
The minimal keystrokes/actions are as follows:

Keystroke Action
Right Arrow Slide camera 1 unit in the positive X direction
Left Arrow Slide camera 1 unit in the negative X direction
Up Arrow Slide camera 1 unit in the positive Y direction
Down Arrow Slide camera 1 unit in the negative Y direction
Shift Up Arrow Slide camera 1 unit in the positive Z ("in") direction
Shift Down Arrow Slide camera 1 unit in the negative Z ("out") direction
Control Down Arrow Change camera pitch by 2 degrees
Control Up Arrow Change camera pitch by -2 degrees
Control Right Arrow Change camera yaw by 2 degrees
Control Left Arrow Change camera yaw by -2 degrees
< Change camera roll by 2 degrees
> Change camera roll by -2 degrees

Note that your navigation will be made much more intelligible if you cover the horizontal plane with a set of grid lines, as in figure 7.24.
To add these grid lines, a simple loop shown below will help:

      for( int x = -100; x < 100 ; x++ )  { 
        glBegin( GL_LINES );
          glVertex3d( x, 0, 100 );
          glVertex3d( x, 0, -100 );
        glEnd( );
      }
      

Some hints:

  • Here is a good reference for keyboard input in OpenGL.
  • You should add both horizontal and vertical grid lines.
  • You may need to develop a camera class.
  • Read section 7.3 of Hill. It describes how to implement a camera class and flying.
  • Hill explains all the camera movement and gives you code for the slide and the roll. You should be able to figure out the pitch and yaw.

Documentation: You must create adequate documentation, both internal and external, along with your assignment. The best way to produce internal documentation is by including inline comments. The preferred way to do this is to write the comments as you code. Get in the habit of writing comments as you type in your code. A good rule of thumb is that all code that does something non-trivial should have comments describing what you are doing. This is as much for others who might have to maintain your code, as for you (imagine you have to go back and maintain code you have not looked at for six months -- this WILL happen to you in the future!).

I use these file and function (method) headers, in my code. Please adopt these (or the official CS ones) for all your assignments. The file header should be used for both ".h" and ".c" (or ".cpp") files.

Create external documentation for your program and submit it along with the project. The documentation does not have to be unnecessarily long, but should explain briefly what each part of your program does, and how your filenames tie in. Most importantly, tell the TA how to compile and run your program.


What to
Turn in:
Submit everything you need to compile and run your program (source files, data files, etc.)

BEFORE YOU SUBMIT YOUR ASSIGNMENT, put everything in one directory on ccc.wpi.edu, compile it, and make sure it runs. Then tar everything up into a single archive file.

The command to tar everything, assuming your code is in a directory "ass3", is:

tar cvf FirstName_LastName_ass3.tar ass3

To submit your work, you will use the turnin utility on CCC. Here is a link to instructions about how to do this. The turnin ID for the "Prep" part is "hw3-prep" and for the "new stuff" part is: "hw3", so to submit your new stuff, you would type something like this when logged in to the CCC machine:

/cs/bin/turnin submit cs4731 hw3 FirstName_LastName_ass3.tar


Academic
Honesty:
Remember the policy on Academic Honesty: You may discuss the assignment with others, but you are to do your own work. The official WPI statement for Academic Honesty can be accessed HERE.


Back to course page.