CS 4465 - Lab (5)
Translation, Rotation, Scaling, etc


Our goals in this lab are:
Preparation
Try to use the same computer you have used before.  You will complete all the activities during the lab.

Different Transformations in OpenGL
Today we look at homogeneous coordinates and the basic translation, scaling and rotation transformations. Translation and rotation are rigid body transformations which preserve lengths and angles. The general affine transformation which multiplies a point in homogeneous coordinates (3rd coordinate = 1) by a matrix with arbitrary values in the first two rows (but last row 0, 0 , 1 as always) preserves parallel lines but not lengths or angles.

Here are the 3D versions of these transformations (Note that these are matrices, so they have [ and ] brackets around them). Also, note that this transformation is the same for a point and a vector:

Translation:

1       0       0      dx
0 1 0 dy
0 0 1 dz
0 0 0 1

Scaling:

sx      0       0      0  
0 sy 0 0
0 0 sz 0
0 0 0 1

Rotation about z-axis:

cos(t)  -sin(t)  0    0
sin(t) cos(t) 0 0
0 0 1 0
0 0 0 1

Rotation about x-axis:

0      0      1      0
0 cos(t) -sin(t) 0
0 sin(t) cos(t) 0
0 0 0 1

Rotation about y-axis:

cos(t)  0   sin(t)   0
0 1 0 0
-sin(t) 0 cos(t) 0
0 0 0 1

These transformations are on the object, not the viewer, but the coordinate frame is always at the viewer. For example, if we translate an object -4 units in the z direction, the transformation is the same as:

Either way the viewer and object are further apart. If we rotate the object by 30 degrees around the y-axis, this means that the world rotates around the viewer by 30 degrees, or that the viewer rotates -30 degrees while the world is stationary. Either way, objects will be seen as moving to the left.

The OpenGL functions for these transformations (rotation) is (e.g.):

void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)

angle  ---  Specifies the angle of rotation, in degrees.
x , y, z ---  Specifies the x, y, and z coordinates of a vector, respectively.
glRotate computes a matrix that performs a counterclockwise rotation of angle degrees about the vector from the origin through the point (x, y, z).

So for example, to rotate by 30 degrees around the y-axis we could call glRotatef(30,0,1,0);

void glScalef(GLfloat x, GLfloat y, GLfloat z)
Specifies scale factors along the x, y, and z axes, respectively.
glScale produces a general scaling along the x, y, and z axes. The three arguments indicate the desired scale factors along each of the three axes. void

glTranslatef
(GLfloat x,  GLfloat y, GLfloat z)
x, y, z Specify the x, y, and z coordinates of a translation vector.
glTranslate
moves the coordinate system origin to the point specified by (x, y, z).

We will begin our OpenGL 3D viewing by constructing a cube. We have to specify 6 polygonal faces (A, B, C, D, E, and F on the figure below), but each vertex will be repeated three times (since it is shared by three faces). If we do a brute-force construction listing all the points our code will repetitious and hard to change. We will list the 8 vertices in an array and then refer to them only by index.  These 8 vertices are identified by 8 (x,y) pairs as shown under Vertices in the figure below. 

Cube2

Cube


We'll also make a unit cube whose vertex coordinates play a two roles as the coordinate of the vertex and as the (r, g, b) component of the colors of the vertex.  Here is idea:

typedef GLfloat point3[3];
//Vertices and the color they represent
point3 p[8]={
{0,0,0}, //black
{0,0,1}, //blue
{1,0,1}, //red+blue - Magenta
{1,0,0}, //red
{0,1,0}, //green
{0,1,1}, //green+blue - Cyan
{1,1,1}, //white
{1,1,0} //red+green - Yellow
};

//Draw a single point
void drawPoint(int i){
glVertex3fv(p[i]);
}

//Draw a faces of the cube - square
void drawFace(int i1,int i2,int i3,int i4){
glBegin(GL_POLYGON);
glColor3fv(p[i1]);
drawPoint(i1);
drawPoint(i2);
drawPoint(i3);
drawPoint(i4);
glEnd();
}

Our display function will include the code:
	drawFace(0,3,2,1); //bottom = black,
drawFace(1,2,6,5); //front = blue
drawFace(2,3,7,6); //right side = magenta
drawFace(3,0,4,7); //back side = red
drawFace(4,5,6,7); //top = white
drawFace(5,4,0,1); //left side = yellow

Below is the progrm that creates the cube similar to the one explained above:

#include <GL/glut.h>
#include <math.h>
typedef GLfloat point3[3];

point3 p[8]={
        {0,0,0},  //black
        {0,0,1},  //blue
        {1,0,1},  //magenta
        {1,0,0},  //red
        {0,1,0},  //green
        {0,1,1},  //green+blue
        {1,1,1},  //white
        {1,1,0}   //yellow
};

void drawPoint(int i){
        glVertex3fv(p[i]);
}
void drawFace(int i1,int i2,int i3,int i4){
        glBegin(GL_POLYGON);
        glColor3fv(p[i1]);
        drawPoint(i1);
        drawPoint(i2);
        drawPoint(i3);
        drawPoint(i4);
        glEnd();
}
       
void myinit(void)
{
 
       /* attributes */
        glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
        glColor3f(0.0, 0.0, 0.0); /* draw in black */
        /* set up viewing */
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-1, 1, -1, 1,-10,10);
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_DEPTH_TEST);
}
void drawCube(){
        drawFace(0,3,2,1);
        drawFace(1,2,6,5);
        drawFace(2,3,7,6);
        drawFace(3,0,4,7);
        drawFace(4,5,6,7);
        drawFace(5,4,0,1);
}

void display( void )
{
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  /*clear the window */
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(-.5,-.5,-.5);
        drawCube();
        glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
        /* Standard GLUT initialization */
        glutInit(&argc,argv);
        glutInitDisplayMode (GLUT_SINGLE| GLUT_RGB|GLUT_DEPTH);

        glutInitWindowSize(500,500); /* 500 x 500 pixel window */
        glutInitWindowPosition(0,0); /* place window top left on display */
        glutCreateWindow("Cube"); /* window title */
        glutDisplayFunc(display); /* display callback invoked when window opened */
        myinit(); /* set attributes */
        glutMainLoop(); /* enter event loop */
}

Lab Activity (1)
Before you run this program I want you to do something on the paper.  Either print this image or get a hard copy from the instructor.   This is a blank cube.   Look at the  code segments I have shown above in font red.  Mark each corner with numbers 0 through 7 in the same order that the vertices are assigned in your program.  Then, mark the color on each of the 6 sides.  Try your best to figure this out as best as you can. 

Cut and paste the above program and run it.  You will see a cube on your screen.  It might be hard to see that the image on the screen is really a cube, because you are looking at one of its side directly from the front.   This is the front side of the cube.   You drew that at:  drawFace(1,2,6,5);
You used the first argument for the color, since the color is blue, then 1 corresponds to (0, 0, 1).  You have to remeber the right-hand rule, so you are going counter-clock-wise in this order: 1 -> 2 -> 6 -> 5. 

I am sure now you can determine whether you have correctly identify all the colors and corners.  But with the above program, you still need to do a few things to confirm your answer.  Hold on and we get to this very soon.

There is a glTranslatef(-0.5,-0.5,-0.5); before the drawCube function call.  Why do we have that? Does that call move the cube to the center of the screen?  Comment that line and run your program again.  I am sure you now can verify what this translation was doing.

Rotation
Suppose we want to rotate the cube by 45 degree around the y-axis.   Based on what we mentioned at the beginning of the lab, the call for this rotation looks like this: 
glRotatef(45, 01, 0);

Did we rotate the cube around the center of the cube or around the origin (I suppose 0, 0, 0)?  Let's run an experiment to answer some of the questions you might have (write on a piece of paper for yourself).  Important: make sure to comment the glTranslatef line before you proceed.  Pay attention to the location where the cube will appear on the screen.

    a) Run the program as is (after commenting the glTranslatf), what is the color of the side you are seeing on the screen?     Side 1: -----------
    b) Rotate the cube by 90 degree around y-axis,
glRotatef(90, 01, 0);  What is the color of the side you see?   Side 2: -----------
    c) Rotate the cube by 90 degree around y-axis once more, now you have two 90 degree rotations, What is the color now?  Side 3: --------
    d) Rotate the cube by 90 degree around y-axis once more, now you have three 90 degree rotations, What is the color now?  Side 4: ---------
    e) Rotate the cube by 90 degree around y-axis once more, What is the color now?  Side ?: ---------

The last rotation should have put you back where you were as by that rotation you have have rotated 360 degrees.  If this didn't happen, then there can be two different problems?
    Problem 1:  You thought you have rotated by 90 around y-axis every time, but somehow that was not the case, i.e., you had a wrong value or incorrect number of                        rotations, or incorrect rotation axis.
    Problem 2:   ___________________  

I hope you know what the second problem is.   What if you had used the same color for more than one face.

Did you notice the way the cube appeared on the screen after each rotation.  Basically the cube appeared on the top-right-hand-side twice (a, b) and on the top-left-hand-side twice (c,d).  This should tell you where the access of rotation was.  So, now you can make sure that all your marks on the paper is correct.

One more experiment.   Try to remove all the rotation statements but keep one:
glRotatef(270, 01, 0);

This rotation is equivalent to which one of the a, b, c, or d above? 

Lab Activity (2)
Let's try something new.  Remove all the rotations and keep only one rotation around y-axis by 90 degree.  Conduct a new experiment by placing the rotation

    a) once by placing it before the glTranslatef(-0.5, -0.5, -0.5);
    b) and another time by placing it after the
glTranslatef(-0.5, -0.5, -0.5);

Did you notice a difference?

Lab Activity (3)
The glTranslatef(1.0, 0.5, 1.0) will scale the cube by 1/2 on the y-axis and will keep the rest of the dimensions unchanged.  Place this call in your program before the drawCube function call to see its effect.

Lab Activity (4)
Before you try start this activity, remove or comment all the rotation and scaling transformation calls.  Please keep the        
glTranslatef(-0.5,-0.5,-0.5); in the program.

Then try the following experiment and compare the results:

    1) Rotate the cube by 45 degree around y-axis
    2) then rotate the resulting cube by 35 degree around z-axis, and
    3) then rotate the resulting cube by 15 around x-axis.

Do you think the result would have been different if you would reverse these steps, i.e, you would do 3, then 2, and finally 1?

Lab Activity (5)
Before you try start this activity, remove or comment all the rotation and scaling transformation calls.  Please only keep the   
glTranslatef(-0.5,-0.5,-0.5); in the program.

Then try the following experiment and compare the results:

    1) Rotate the cube by 45 degree around y-axis
    2) Translate the resulting cube by 0.5 on y axis
    3) then rotate the resulting cube by 30 aroud z-axis

Do you think the result would have been different if you would reverse these steps, i.e, you would do 3, then 2, and finally 1?