CS 5721 - Computer Graphics

Homework 4: Matrices, Viewing, and Projections
Due Date:
Oct. 22, 2007 (100 pts)

Description

In this assignment, you will create 3D scenes containing objects and render those scenes to your FrameBuffer class using orthographic and perspective viewing transforms. This assignment builds upon your previous assignments and will require the use of your Vector classes, FrameBuffer class, as well as your line drawing code. We will not use the triangle drawing code for this assignment.

There are several steps to this assignment, which are outlined below:

  • Step 1: create 4D (homogeneous) vectors and 4x4 matrices
  • Step 2: create classes for basic 3D objects: triangle, plane, cube, pyramid, and sphere
  • Step 3: build the orthographic viewing transform
  • Step 4: build the perspective viewing transform

Important Notes and Considerations

At first glance, this assignment probably appears to be quite large. However, the bulk of the work for this assignment rests in doing a good job on Step 1. Building the classes for homogeneous vectors along with the 4x4 matrices is the key to easily completing this assignment. You will also need to spend time on Step 2 to make good organization of the classes. Once these classes are built, implementing the orthographic and perspective viewing transforms will quite simple.

HVector (or Vector4), Matrix4x4

You will need to create two linear algebra-based classes for this assignment: HVector (or Vector4) and Matrix4x4. The HVector is the implementation of the homogeneous coordinate vector (a 4D vector) discussed in class, which means that for positions and locations, the 4th coordinate (w) will be 1.0. For offsets and directions, it will be 0.0. For the most part, the HVector class will resemble your Vector3D class.

The second class, Matrix4x4, will be used to represent homogeneous transforms. Your class should contain as private data, a 2D array of doubles:

double d[4][4]

to represent the values in the matrix. You can also represent it with a double d[16] if you like. Among other functions that you deem useful, you must implement the following member functions:

void set( 16 doubles ); // sets the 16 values in the matrix 
void set2Identity(void); // clears the matrix to the identity matrix
Matrix4x4 transpose(void); // returns the transpose
Matrix4x4 inverse(void); // returns the inverse of the matrix double get(int i, int j); // returns the value at index i,j void makeTranslate( Vector3D& ); // sets the matrix to the translation matrix void makeRotateZ( double theta_in_deg ); // creates the Z rotation matrix void makeRotateY( double theta_in_deg ); // creates the Y rotation matrix void makeRotateX( double theta_in_deg ); // creates the X rotation matrix void makeScale( Vector3D& ); // creates the scale matrix void makeOrtho( ... ); // creates the orthographic viewing matrix void makePerspective( ... ); //creates the perspective viewing matrix

For the last two functions, you will need to determine which parameters to provide to the function. In the functions themselves, I suggest you build the matrices using multiplication of matrices, such as shown in Equation 7.4 of the book.

The constructor should be used to set the values of the matrix. You should also implement the operators (+, -, *) which take Matrix4x4 as arguments so you can add, subtract, or matrix multilply two Matrix4x4s. You should also implement the * operator so Matrix4x4s can be used to multiply HVectors and scalars. This will allow you to perform operations like the following:

HVector v, u;
Matrix4x4 M, M1, M2;
....
M = M1 * M2; // two matrices multiplied
u = M * v; // v transformed by M into u

The last two operations are very important to get right! If these functions work correctly, implementing the orthographic and perspective viewing is very simple. Remember that we have been performing post multiplication of vectors in class.

3D Objects

For this assignment, I want you to create some simple polygonal 3D objects: triangle, plane, pyramid, cube, and sphere. (If you get the assignment done early and feel energetic, you can add additional objects for extra credit - be sure to document and demonstrate any objects you do add.) You will be rendering these objects in wireframe ONLY, meaning that after you have applied the viewing and projection matrices, you will only draw lines representing the edges of the objects. One way to do this is to create classes for each object, such as Triangle or Cube, derived from a base object. For instance, my triangle class has the following definition:

class Object3D
{
public:
   virtual void transform(const Matrix4x4& mat) = 0;
   void getLineSegment(int idx, HVector& p, HVector& q) = 0;
};


class Triangle : public Object3D
{
public:

   Triangle();  // creates unit triangle
   Triangle(const Vector3D& pt0, const Vector3D& pt1, const Vector3D& pt2);
   void set(const Vector3D& pt0, const Vector3D& pt1, const Vector3D& pt2);
   void get(HVector& pt0, HVector& pt1, HVector& pt2);

   void transform(const Matrix4x4& mat);

   std::vector<HVector> vertices;
};

Deriving from the base object class will give us functionality that we can use in the next assignments and isn't strictly necessary now. The most important function to implement in these object classes is the transform function, which will simply apply the Matrix4x4 transform to all of the vertices in the object.

The Plane, Pyramid, Cube, and Sphere classes should be similarly implemented and benefit from the Triangle class. A plane is made up of 2 Triangles, a Pyramid from 4 Triangles, a Cube from 12 triangles, and so on.

I also suggest that your 3D objects default constructor create an base of object of "unit" length. In other words, have it inside the unit sphere so that it's size is well known. This will allow you to easily use scale matrices to construct well known larger sized objects.

When it is time to draw the triangle edges to your FrameBuffer class, you should only draw lines between the vertices, hence the function in my example Triangle class called "getLineSegment". This gives me an easy way to extract the line segments in the object so I can draw them.

Image 1 and 2 - Orthographic Projection

You will need to generate two sets of images using orthographic projection. In the first image, you will use the base orthographic projection detailed on page 163 of the book. After you get this working, you will need to implement the viewing based version of the orthographic projection, outlined in Section 7.2.1. In these images, you need to use all of your 3D objects.

Image 3 and 4 - Perspective Projection

You will need to generate two image of a perspectively viewed scene. You should follow the information in Section 7.3 of the book for this step. In these images, you need to use all of your 3D objects.

Image 5 - Creative Image

Using a perspective view, create a 3D scene that looks like an outdoor scene. Use all of your 3D objects. The total number of objects need to be 10 or greater. Very interesting scenes will receive up to 5 points of extra credit.

Grading

There are 100 points in this assignment and they will be broken down as follows:

  • Code appears correct and compiles - 30pts
  • Code executes correctly - 30pts
  • Test images correctly generated and 3D objects are implemented - 30pts
  • Creativity - 10pts

Testing

I am preparing a single test case in each of the two projections that you can use to help test your code. The transformations described with each object are specified in the order in which they need to be applied to the object.

Case 1 - Orthographic Projection

Orthographic parameters

nx = 500, ny = 500
t = 12, b= -12, l=-12, r=12, n=0, f=-20

There is no view matrix in this case.

Objects

  1. Cube 1: Translate(8,-8,8)
  2. Cube 2: RotateZ(50), RotateY(50), Translate(8,8,-8)
  3. Cube 3: RotateX(65), RotateY(12), Translate(-8,8,-8)
  4. Cube 4: RotateY(45), Translate(-8,-8,-8)
  5. Triangle: Scale(2.25, 0.5, 2.25), Rotate(45)

In this case, you should see output similar to the following image. Note that due to small differences with how you draw lines or generate your geometry, your image may look slightly different.

Case 2 - Perspective Projection

Objects

  1. Cube 1 - Scale(2,2,1), Translate(-1, -1, -2)
  2. Cube 2 - Scale(2,2,2), Translate(-1, -1, -5)
  3. Cube 3 - RotateZ(45), Scale(2,2,2), Translate(-1, -1, -10)
  4. Cube 4 - RotateX(60), Scale(2,2,2), Translate(-1, -1, -15)
  5. Cube 5 - Scale(2,2,2), Translate(-1, -1, -30)

In this case, you should see output similar to the following images. Note that due to small differences with how you draw lines or generate your geometry, your image may look slightly different. Also note that your choice of the up vector will influence the orientation of the image, so that may affect the similarity of your output versus the test cases.

Perspective Parameters

nx = 500, ny = 500
t=4.25, b=-4.25, l=-4.25, r=4.25
n=-1.5, f=-50.0

View Parameters - This is just the default view looking down the -Z axis

eye = (0, 0, 0, 1)
gaze = (0, 0, -1, 0)

View Parameters - Same set of objects, but viewed a little higher up in Y still looking down -Z

eye = (0, 1.5, 0, 1)
gaze = (0, 0, -1, 0)

View Parameters - Same set of objects. Same as previous view, but now over a little in X

eye = (1.5, 1.5, 0, 1)
gaze = (0, 0, -1, 0)

View Parameters - Same set of objects. Same as previous view, but now with a different gaze direction

eye = (1.5, 1.5, 0, 1)
gaze = (-0.2, -0.1, -1, 0)

View Parameters - Same set of objects. Same as previous view, but now farther away in Z

eye = (1.5, 1.5, 5, 1)
gaze = (-0.2, -0.1, -1, 0)

**NOTE: In the perspective test case, not all of the gaze directions are normalized so be aware of that when you create your orthonormal basis.

What to Turn In

Assignments must be received before class starts on the due date.

You need to turn in ALL of your code for this assignment. This includes any C++ files along with the main.cpp file that tests your code. We MUST know how to compile your program. It is easiest if you create a README.txt file in your submission that describes how to compile the program. If you use any additional files (like project files from Visual C++/.Net/Makefiles/Whatever) you must include these as well.