Introduction to OpenGL Transformations

Now that we have the basics of OpenGL down, i'm going to explain how to draw a cube and rotate it.  

First we need to figure out how to draw a cube.  Remember that we draw everything in openGL as triangles, so it will take two triangles to make a single face on a cube.  Therefore we will need to draw 12 triangles.  It doesn't matter what order we draw the triangles in, but we want to draw them all counter-clockwise.  The face of the cube that is facing up is made up of two triangles with the points:

Triangle 1: -5.0, -5.0, 5.0

5.0, -5.0, 5.0

5.0, 5.0, 5.0

Triangle 2: 5.0, 5.0, 5.0

-5.0, 5.0, 5.0

-5.0, -5.0, 5.0

Which looks like:

______

|         /|

|  2   /  |

|     /    |

| /    1|

| / ____ |

Notice the z is 5.0.  This draws the front face 5 units out of the screen.  We do this so the cube's center point will be at 0,0,0 so it will rotate nicely.

The next face we'll draw is the back face.  This face is facing away from us, so we are looking at the backside !  We would draw it as follow:

Triangle 3: 5.0, -5.0, -5.0

-5.0, -5.0, -5.0

-5.0, 5.0, -5.0

Triangle 4: -5.0, 5.0, -5.0

5.0, 5.0, -5.0

5.0, -5.0, -5.0

Which looks like:

______

|\         |

|  \  4  |

|     \    |

|   3  \  |

| _____\|

As you can see, this is backwards to us.  But you have to rotate the object 180 degrees around Y so it is facing you.  Also note that the Z is -5.0 which is 5 units into the screen.

The other 4 faces will be done similarly.  To help us see each face of the cube more clearly, we'll give each face a different color by calling glColor3f(float r, float g, float b).  Here's the code for all the faces:

....

void renderScene()

{

 // clear the color and depth buffers

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 // delete our old transformations

 glLoadIdentity();

 // start drawing !

 //  we are going to draw in trinagles

 glBegin(GL_TRIANGLES);

   //front face

   glColor3f(0.0, 0.0, 1.0); // change the color to blue

   glVertex3f(-5.0, -5.0, 5.0);

   glVertex3f(5.0, -5.0, 5.0);

   glVertex3f(5.0, 5.0, 5.0);

   glVertex3f(5.0, 5.0, 5.0);

   glVertex3f(-5.0, 5.0, 5.0);

   glVertex3f(-5.0, -5.0, 5.0);

   // back face

   glColor3f(1.0, 0.0, 0.0); // red

   glVertex3f(5.0, -5.0, -5.0);

   glVertex3f(-5.0, -5.0, -5.0);

   glVertex3f(-5.0, 5.0, -5.0);

   glVertex3f(-5.0, 5.0, -5.0);

   glVertex3f(5.0, 5.0, -5.0);

   glVertex3f(5.0, -5.0, -5.0);

   // right side

   glColor3f(0.0, 1.0, 0.0); // green

   glVertex3f(5.0, -5.0, 5.0);

   glVertex3f(5.0, -5.0, -5.0);

   glVertex3f(5.0, 5.0, -5.0);

   glVertex3f(5.0, 5.0, -5.0);

   glVertex3f(5.0, 5.0, 5.0);

   glVertex3f(5.0, -5.0, 5.0);

   // left side

   glColor3f(1.0, 0.0, 1.0); // purple

   glVertex3f(-5.0, -5.0, -5.0);

   glVertex3f(-5.0, -5.0, 5.0);

   glVertex3f(-5.0, 5.0, 5.0);

   glVertex3f(-5.0, 5.0, 5.0);

   glVertex3f(-5.0, 5.0, -5.0);

   glVertex3f(-5.0, -5.0, -5.0);

   // top face

   glColor3f(1.0, 1.0, 0.0); // yellow

   glVertex3f(-5.0, 5.0, 5.0);

   glVertex3f(5.0, 5.0, 5.0);

   glVertex3f(5.0, 5.0, -5.0);

   glVertex3f(5.0, 5.0, -5.0);

   glVertex3f(-5.0, 5.0, -5.0);

   glVertex3f(-5.0, 5.0, 5.0);

   // bottom face

   glColor3f(0.0, 1.0, 1.0); // blue-green

   glVertex3f(-5.0, -5.0, -5.0);

   glVertex3f(5.0, -5.0, -5.0);

   glVertex3f(5.0, -5.0, 5.0);

   glVertex3f(5.0, -5.0, 5.0);

   glVertex3f(-5.0, -5.0, 5.0);

   glVertex3f(-5.0, -5.0, -5.0);

 glEnd(); // done drawing

 // swap the buffers so we can see what was drawn !

 SDL_GL_SwapBuffers();

}

....

When you try to run this, you'll notice that you don't see anything !  This is because our camera is at 0,0,0 and our cube starts from 5.0 to -5.0.  We could do what we did in the last example and draw everything with a Z that is further away (-25), but this can mess up transformations, as transformations are done about the origin.

Instead of specifying a Z, we'll transform our whole object 25 units away from the camera in the Z.  Then we will be able to see it.

There are 3 common types of transformations in opengl: translate, rotate, and scale.  We'll start off looking at the translate routine.

The translate routine is:

glTranslatef(float x, float y, float z);

We want to move our object 25 units away from us, so that would be -25 units in the Z.  We will call the function as follows:

glTranslatef(0.0, 0.0, -25.0);

To translate our object, we put the glTranslatef() function right before we draw our cube.  This will translate the whole cube.

There are a couple important things to remember.  The first is that once we call glTranslatef(), every single object that is draw after that call, is translated.  

When you call glTranslatef(), openGL is actually taking the translation matrix with the translation values you passed it, and multiplying it to the current modelview matrix.  The matrix just keeps getting multiplied on to, until you call glLoadIdentity().  If we did NOT call glLoadIdentity() at the beginning of our renderScene() function, everytime time we draw our scene, it would get translated back another -25 units in the Z.  We do NOT want that, so we clear our modelview matrix every time we draw, and reapply the transformation.

So, everytime we call glLoadIdentity(), it's actually moving our object back to its original position around the origin, where we then move it -25 units in the Z.

Here's the code to actually view our object:

....

 glLoadIdentity();

 // start drawing !

 //  we are going to draw in trinagles

 

 // translate our object back into the screen so we can see it

 glTranslatef(0.0, 0.0, -25.0);

 glBegin(GL_TRIANGLES);

   //front face

....

Now it's time to rotate our cube.  We use the function:

glRotatef(float degrees, float xaxis, float yaxis, float zaxis);

The first parameter is how many degrees you want to rotate the object.  The next 3 parameters specify the axis you want to rotate around.  If you want to rotate around the Y axis by 30 degrees, the call would be:

glRotatef(30, 0.0, 1.0, 0.0);

The above call would cause our cube to rotate 30 degrees, then stop.  We want our cube to continuously rotate.  Since we clear our modelview matrix everytime we draw using glLoadIdentity(), everytime we draw, we need to make the angle of rotation slightly bigger.

Let's create a new global variable called rotateY.

....

int videoFlags;

double rotateY = 0.0; // holds the y rotation value

bool initializeSDL(); // return true on sucess

....

At then end of our renderScene function, lets increment the rotateY by 0.1.  While this seems very small, if you are drawing 100 frames per second, you are rotating your object 10 degrees every second !

....

 // swap the buffers so we can see what was drawn !

 SDL_GL_SwapBuffers();

 // increment our Y rotation value

 rotateY += 0.1;

}

....

Now, here is the tricky part.  Where do we put the glRotate() call.  We obviously need to put it before we draw our object, but do we want it before or after are glTranslate() call?  Order of operations is extremely important in opengl.  As I said in an earlier tutorial, all transformations are done but multiplying with the modelview matrix.  In matrix multiplication, it matter whether you multiply the rotation matrix first or the transformation matrix first !

Lets first try it putting the glRotatef before the glTranslatef();

....

 glLoadIdentity();

 // start drawing !

 //  we are going to draw in trinagles

 

 // rotate our object about the y axis

 glRotatef(rotateY, 0, 1, 0);

 // translate our object back into the screen so we can see it

 glTranslatef(0.0, 0.0, -25.0);

 glBegin(GL_TRIANGLES);

....

As you can see, that is not what we wanted.  A good way to think about transformations in opengl is that they happen backwards.  

What we wanted, was for our object to rotated about it's center which is 0,0,0 (the origin), then translate back -25 units in the z direction.  This would make the cube spin.

When we specified the rotate first, opengl actually translated our object -25 units in the z first, then rotated the object about 0,0,0 (the origin) which is why the object was orbiting about the origin (where the camera is).

If we put the glRotatef() after the glTranslatef(), the cube should now spin in place -25 units in the z.

....

 glLoadIdentity();

 // start drawing !

 //  we are going to draw in trinagles

 

 // translate our object back into the screen so we can see it

 glTranslatef(0.0, 0.0, -25.0);

 // rotate our object about the y axis

 glRotatef(rotateY, 0, 1, 0);

 glBegin(GL_TRIANGLES);

....

Now lets add a little X rotation also so that we can see the top and bottom of the cube to.  First create a new global variable called rotateX;

....

double rotateY = 0.0; // holds the y rotation value

double rotateX = 0.0; // holds the x rotation value

bool initializeSDL(); // return true on sucess

....

Increment the value in the renderScene function:

....

 // increment our Y rotation value

 rotateY += 0.1;

 rotateX += 0.1;

}

....

Add another call to glRotatef() using the rotateX as the degrees and also about the X axis this time !  The glRotatef call also needs to be after the glTranslatef(), but in this case it doesn't matter whether we rotate about the Y axis first or the X axis.

....

 // translate our object back into the screen so we can see it

 glTranslatef(0.0, 0.0, -25.0);

 // rotate our object about the y axis

 glRotatef(rotateY, 0, 1, 0);

 // rotate our object about the x axis

 glRotatef(rotateX, 1, 0, 0);

 glBegin(GL_TRIANGLES);

....

Now you can see our object rotating in multiple directions !

Compile this code with:

g++ -o GLTransformations GLTransformations.cpp `sdl-config --cflags --libs` -lGL -lGLU

Download the source code here