This lab is an introduction to Matrix Transformation
After the lab lecture, you have approximately two weeks of time to:
Each vertex of polygons will pass through two main stages of transformations:
There is one global matrix internally for each of the two stage above:
Given a 3D vertex of a polygon, P = [x, y, z, 1]^{T}, in homogeneous coordinates, applying the model view transformation matrix to it will yield a new coordinate:
P’ = [x’, y’, z’, 1]^{T} = M_{modelview}*P.
By applying projection to P’, a 2D coordinate in homogeneous form is produced:
P” = [x”, y”, 1]^{T} = M_{projection}*P’.
The final coordinate [x”, y”] will be a point on the screen to be drawn.
Each matrix can be, and should be, initialized to identity at the beginning of an application.
For example, setting the model view matrix to the identity matrix can be done by:
glMatrixMode(GL_MODELVIEW); //selecting the global matrix to be modified glLoadIdentity(); //set the currently selected global matrix to identity
Similarly, we can set the projection matrix to identity as well:
glMatrixMode(GL_PROJECTION); glLoadIdentity();
These two global transformation matrices can be modified by the following elementary transformation functions as required by individual applications.
glTranslate*(dx, dy, dz);
where [dx, dy, dz] is the translation vector.
The effect of calling this function is to concatenate the translation matrix defined by the parameters [dx, dy, dz] to the global model view matrix:
Where T(dx, dy, dz) =
In general, a new transformation matrix is always concatenated to the global matrix from the right. This is often called post-multiplication.
glRotate*(angle, x, y, z)
Where angle is the angle of counterclockwise rotation in degrees, and x, y and z define a vector(originating at the origin) to rotate about.
Typically we rotate about only one of the major axes, which simplifies x, y and z to be a unit vector.
For example, if we want to rotate about the x-axis, then x=1, y=0, and z=0.
The effect of calling a rotation matrix is similar to translation. For example, the function call:
glRotatef(a, 1, 0, 0);
will have the following effect:
M_{modelview} = M_{modelview} * R_{x}(a);
Where R_{x}(a) denote the rotation matrix about the x-axis for degree a: R_{x}(a) =
Rotations about the y-axis or z-axis can be achieved respectively by functions calls:
glRotatef(a, 0, 1, 0); // rotation about the y-axis glRotatef(a, 0, 0, 1); // rotation about the z-axis
glScale*(sx, sy, sz);
where sx, sy and sz are the scaling factors along each axis with respect to the local coordinate system of the model. The scaling transformation allows a transformation matrix to change the dimensions of an object by shrinking or stretching along the major axes centered on the origin.
Example: to make the wire cube three times as high, we can stretch it along the y-axis by a factor of 3 by using the following commands.
// make the y dimension 3 times larger glScalef(1, 3, 1); // draw the cube glutWireCube(1);
Example: Suppose we want to rotate a cube 30 degrees and place it 5 unit length away from the camera for drawing. You might write the program intuitively as below:
// first rotate about the x axis by 30 degrees glRotatef(30, 1, 0, 0); // then translate back 5 glTranslatef(0, 0, -5); // use the GLUT library's cube routine to draw // a cube centered(by default) at the origin
The following figure shows that:
If you run this program, you might be surprised to find that nothing appears in the picture! Think about WHY.
If we modify the program slightly as below:
// first translate back 5 glTranslatef(0, 0, -5); // then rotate about the x axis by 30 degrees glRotatef(30, 1, 0, 0); // use the GLUT library's cube routine to draw // a cube centered(by default) at the origin
The following figure shows that:
glTranslatef(0, 0, -5); glRotatef(30, 0, 1, 0); DrawTheModel();
Using the local coordinate, we first move the local coordinate's origin down the negative z-axis by 5 units and then rotate that coordinate system about y-axis by 30 degrees.
Using the global coordinate, we first rotate the global coordinate system about its origin by -30 degrees, then move the global coordinate system's origin down the positive z-axis by 5 units. The model is fixed, but the global coordinate system is rotated and translated. The viewpoint locates at the origin of the global coordinate system. Remember that in the global coordinate approach, the order is reversed, and the orientation order is also reversed.
The following is the local approach to a rotation:
The following is the global approach to a rotation:
The gluLookAt() Function: define a viewing transformation
void gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz )Parameters
eyex, eyey, eyez: specifies the position of the eye point; centerx, centery, centerz: specifies the position of the reference point; upx, upy, upz: specifies the direction of the up vector.
Note that, these parameters are equivalent to the camera parameters specified in the textbook:
The gluLookAt() function makes it easy to move both the "from" and the "to" points in a linear manner. For example, if you need to pan along the wall of a building located away from the origin and aligned along no axes in particular, you could simply take the "to" point to be one corner of the building and calculating the "from" as a constant distance from the "to" point. To pan along the building, just vary the "to" point.
M_{modelview} = M_{viewing} * M_{modeling}
What this means is that your viewing transformations must be entered into the Modelview matrix before modeling transformations.
Three OpenGL commands are provided to directly manipulate the current matrix: glLoadIdentity(), glMultMatrix*() and glLoadMatrix*(). The glMultMatrix*() is used to perform matrix multiplication. glMultMatrix*(m) multiplies the current matrix with the one specified in m. That is, if M is the current matrix and T is the matrix passed to glMultMatrix, then M is replaced with MT. glLoadMatrix*(m) replaces the current matrix with the one specified in m. In the array m, the elements are stored in column order, whereas arrays in C or C++ are stored in row order. Do not be confused about these.
Viewport Transformation
For viewport transformations, glViewport() takes four parameters, which used to specify the lower-left corner coordinates and the width and height of the viewport. Since Windows sends a WM_SIZE message before it sends a WM_PAINT message, the WM_SIZE handler is the ideal place to set the viewpoint parameters and the projection transformation parameters. In the MFC class structure the current view class has an Onsize() member that is good for handling the viewport configuration.
Projection Transformation
Projection Transformations: OpenGL provides two methods of converting 3D images into 2D ones.
OpenGL's perspective projection is created by a couple of commands. The first is glFrustum().
void glFrustum( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far ) Parameters: left, right: Specify the coordinates for the left and right vertical clipping planes; bottom, top: Specify the coordinates for the bottom and top horizontal clipping planes; near, far: Specify the distances to the near and far depth clipping planes. Both distances must be positive.
glFrustum() describes a perspective matrix that produces a perspective projection. (left, bottom, -near) and (right, top, -near) specify the points on the near clipping plane that are mapped to the lower left and upper right corners of the window, respectively, assuming that the eye is located at (0, 0, 0). -far specifies the location of the far clipping plane. Both near and far must be positive.
The following shows perspective viewing volume and the glFrustum() parameters
Although glFrustum() is powerful, it is not very intuitive, OpenGL also presents a much simpler perspective command, called gluPerspective(). Like glFrustum() it generates a perspective viewing volume but in a much simpler way.
void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ) Parameters: Fovy: Specifies the field of view angle, in degrees, in the y direction; Aspect: Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height); ZNear: Specifies the distance from the viewer to the near clipping plane (always positive); ZFar: Specifies the distance from the viewer to the far clipping plane (always positive).
gluPerspective() specifies a viewing frustum into the world coordinate system. In general, the aspect ratio in gluPerspective should match the aspect ratio of the associated viewport. For example, aspect=2.0 means the viewer's angle of view is twice as wide in x as it is in y. If the viewport is twice as wide as it is tall, it displays the image without distortion.
The following shows perspective viewing volume and the gluPerspective() parameters
The following program can be created in Visual Studio using these instructions:
// main.cpp // // This is an example of a program using glut #include <GL/glut.h> void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glLoadIdentity(); /*clear the matrix */ /*viewing transformation*/ gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); glBegin(GL_LINES); glColor3f(1.0f,0.0f,0.0f); //y is red glVertex3i(0,2,0); glVertex3i(0,-2,0); glColor3f(0.0f,1.0f,0.0f); //x is green glVertex3i(2,0,0); glVertex3i(-2,0,0); glColor3f(0.0f,0.0f,1.0f); //z is blue glVertex3i(0,0,2); glVertex3i(0,0,-2); glEnd(); // The following command ensures that the drawing commands are // actually executed rather than being stored in a buffer // awaiting additional OpenGL commands glFlush(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }The above code draws a basic coordinate system with a green x-axis, a red y-axis, and a blue z-axis.
For more on glut*() see the on-line manual.
Start with the example code provided in section G above and make the following changes. Write your answers to the questions in steps 1, 2, 4 and 11.
/5 marks
Click here for some code that draws a robot arm.
/5 marks