Lesson 2

Movement and sizing.

In this lesson we take what we learned in lesson 1 and build on it. We will learn about transformations. Transformations as you might have guessed, transform the matrix. Transformations are how we move and resize objects in our scene.

You can continue with the lesson 1 project you've already created. For continuity and to allow you to download the lessons as separate projects I will be showing the new code in a new project called Lesson2.

If you didn't do lesson 1 you can get it here.

First lets do a simple transformation. we will rotate the cube a small amount on each loop of the render function. This type of animation is frame rate dependant. Frame rate is the measure of how many frames per second are being painted to the scene. What this means for us is that the faster the system you are using the faster the cube will spin. We will learn a better way to do animations later that will be time dependant and will animate at a constant rate irregardless of system speed, but we will tackle the harder stuff later.

Click on the class tab and expand the MFCopenGL class. Double click on the display function. The display function is our render loop. Whatever code we put in the display function will be run over and over in a loop that's why its called a render loop.

Right after the "glEnable(GL_DEPTH_TEST);" put glRotatef( 1, 1.0, 0.0, 0.0 );//rotate 1 degrees about the X axis

glRotatef takes float parameters. The first parameter is the number of degrees to rotate. The next three parameters tell glRotatef what axis to rotate about, x, y, or z respectively.

Now we need to tell glut to redraw the screen. We do this with the glutPostRedisplay command. Place "glutPostRedisplay();" right before the "glutSwapBuffers();"

Keep in mind that OpenGL is a state based machine that uses a stack to hold the matrix. That means we put the machine into a state and then have it do something. In this case we are telling it to rotate and giving it a matrix with a frame cube in it to rotate. Since we are not saving the matrix, (we will discuss how to save the matrix later in this lesson) the matrix with the frame cube gets rotated by 1 degree more on each render pass.

Your display function should look like this.

Go ahead and compile, run and press the play button. You should see the cube rotating about the horizontal axis (that's the X axis).

Now lets go ahead and add rotations on the other 2 axis. See if you can do it on your own before scrolling down to see the code.

Try making the cube rotate at different speeds on the different axis.

Play around with it. It's good to experiment with code to get a feel for what is happening. 

*

*

No peeking!

*

*

*

Ok here's one example of the code for spinning on all 3 axis.

Now you may be saying "Ok spinning it was cool but how do I move it around?" That's what we are going to tackle now.

The function to move objects is glTranslatef. If your starting to see a pattern in the function names you're right there is one. Functions start with gl or glut depending on which API the function is from and functions end in "f "or "d" to show if the take floats or doubles as input.

Add "glTranslatef(0, 0, -1);" just prior to the glRotate calls. The reason we are using -1 it so the cube will move away from us. In OpenGL X is positive to the right, Y is positive up and Z is positive toward us. So if we want an object to move away from us we need to move it in the negative direction on the Z axis.

Go ahead and compile, run and press the play button. 

But wait! why does it keep moving away? Remember what I said about not saving the matrix? Now it has come back to bite us. While it was a nice short cut for animating a rotation it causes a problem for us now that we only want to move the object one time. Here's how we fix this. We push (save) the matrix before doing something and then pop (restore) the matrix afterward. OpenGL uses a state based stack architecture. So to save a matrix we push it onto the stack and to restore a matrix we pop it back off. There is a limit to how many pushes we can nest but you shouldn't run into it under normal circumstance. If you find yourself nesting more that 5 or 6 pushes deep you should examine you code to see if its really necessary.

Add "glPushMatrix();" between glEnable(GL_DEPTH_TEST); and the first transform call. Change glTranslatef(0, 0, -1) to glTranslatef(0, 0, -100) since we are only going to move once we need to make it enough to be noticable.

After "glutWireCube(30);" put  "glPopMatrix();" I also like to indent the code inside the stack push so it reminds me of where we are in the stack. This way we can make sure we always have a glPopMatrix for every glPushMatrix.

Go ahead and compile, run and press the play button. 

Ok it moved where I wanted but now it stopped rotating. Yep that's right, since we are saving the matrix, the transforms are applied only once, or more precisely they are performed repeatedly but on the same original matrix resulting in the same resultant matrix every time.

Lets see what we can do to get our animated rotation back. What we need is to remember how much we have rotated and add to it on each render pass.

Create 3 private float variables in your MFCopenGL. Click the class tab and expand the MFCopenGL class. Right click on the MFCopenGL class, choose add and add variable. Select private and float make the name rotationX and put in an appropriate comment. Add variables for rotationY and rotationZ.

Now in the display function change the glRotatef to use the new variables we have created.

glRotatef( rotationX, 1.0, 0.0, 0.0 );//rotate about the X axis
glRotatef( rotationY, 0.0, 1.0, 0.0 );//rotate about the Y axis
glRotatef( rotationZ, 0.0, 0.0, 1.0 );//rotate about the Z axis

After the "glPopMatrix();" add

rotationX = rotationX + 1;
rotationY = rotationY + 2;
rotationZ = rotationZ + 4;

This will increment the rotation on each pass of the render loop. That way each time the rotation transformation is done on the original matrix the amount of the rotation is greater than the previous iteration.

Go ahead and compile, run and press the play button. You should see our cube is rotating again and stays in place -100 units on the Z axis.

Try changing the glTranslatef(0, 0, -100) to other values and rerunning it you will see that you now have control of the position of the spinning cube.

Note: Since 360 degrees is the same as 0 degrees lets go ahead and put range limit on our rotation so we don't go into overflow on the float and have the rotation direction reverse. As you may recall a float is a signed type of variable and when it reaches its maximum value it will roll over into negative values. There are lots of ways to do this including using the Modulus operator "%" which would run fast. However, for clarity we will use a simple logical operation.

Add these lines after the rotation incrementing.

if(rotationX >= 360) rotationX = 0;// this keeps out rotation in the range of 0 to 360 degrees
if(rotationY >= 360) rotationY = 0;// this keeps out rotation in the range of 0 to 360 degrees
if(rotationZ >= 360) rotationZ = 0;// this keeps out rotation in the range of 0 to 360 degrees
if(rotationX < 0) rotationX = 359;// this keeps out rotation in the range of 0 to 360 degrees
if(rotationY < 0) rotationY = 359;// this keeps out rotation in the range of 0 to 360 degrees
if(rotationZ < 0) rotationZ = 359;// this keeps out rotation in the range of 0 to 360 degrees

Why are we using ">= "and "<" and not just " ="? We are using floats and at some point later we may change the increments to a value that is not factor of 360. In which case if the increment is not a factor of 360 then the increment would pass by our check value and never equal it. By using ">=" we can be sure that no matter what happens the increment will not exceed 360. Also, we may wish to change the direction of the rotation, in which case our increment would be negative and we need to cap out value at 0.

To show how the various transforms effect our scene lets use a technique referred to as commenting out. What this entails is using "//" in front of a line of code to prevent it from executing temporarily. Comment out the first 2 rotation transformations. This will allow us to isolate the third rotation for experimentation.

Run the program and you should see the cube head on and rotating counter clockwise.

Change the increment on the Z rotation to a -4.

 Compile and run and you should see the cube head on and rotating clockwise.

Use the comment out trick and modify each of the transforms in turn so you can see what effect each has to the position and rotation or the object in our scene. 

See if you can move the cube to the upper left corner of the scene and reverse all the rotations. Remember - X will move it to the left and positive Y will move it up. Did you get it to look like this?

Here's the code in case you are having trouble.

Next we will change the size of our object. To do this we use glScalef, this function takes in 3 float value that are the scalars for the X, Y and Z size transformations. Lets make the cube half sized. "Add glScalef(0.5,0.5,0.5);" after the glPushMatrix call.

That's it for this lesson. On your own you might want to try moving the cube around and distorting it's size on various axis independently.

You can download the source code for this lesson here.