Previous Section  < Day Day Up >  Next Section

Rotation

There are actually two different approaches to rotating objects. One method uses quaternions, but the math is complex. The other method is very similar to that of scaling and translating, because it uses a similar matrix equation. This second method is called Euler rotation (pronounced "oiler rotation," not "yewler"). You'll set up a matrix equation first in 2D and then in 3D. As soon as the matrix equation is set up, all you have to do is plug in the vertices one at a time and multiply the matrices to find the new position.

2D Rotation

graphics/06equ25.gif


where q is the angle of rotation.


As soon as you know the angle of rotation, you can take the sine and cosine and turn them into decimal numbers so that you can multiply the matrices. You might need to revisit Chapter 3, "Trigonometry Snippets," for a discussion of angles. Remember that positive angles rotate counterclockwise, and negative angles rotate clockwise. Also, if you know the angle ahead of time and you're calculating the sine and cosine, you can leave the angle in degrees. However, if the computer program is fed the angle and it must take the sine and cosine, remember that the angle must be in radian measure.

Programming Transformations Using Matrices

When using the widely accepted math.h header, key functions such as sine and cosine have arguments that accept their parameters in radians. It's important to properly format the values passed to these functions before asking them to do any calculations. Here are a couple of quick macro functions that you can use when needed:


#define RadsToDegrees( radian ) ((radian) * (180.0f / M_PI))

As you probably recognize, this first method takes a radian argument and returns a degree conversion. More on the definition of M_PI in just a moment.


#define DegreesToRads( degrees ) ((degrees) * (M_PI/ 180.0f))

This function does the reverse and gives us radian arguments for our degree values.

The usage of M_PI comes from the math.h header. Make sure that you not only include the math header in your programs, but also set the directive to use the math header definitions for things like PI. The listed term M_PI comes from the math header and is used to represent pi throughout the chapter. If the math header defines are supported on your platform, you should be able to access them like this:


#define _USE_MATH_DEFINES

#include <math.h>

It's important to set the USE_MATH_DEFINES definition before you include the library so that it knows in advance to work with those parameters.


Example 6.9: 2D Rotation

Set up a general matrix equation that will rotate 2D objects 90°, and then use it to rotate the triangle pictured in Figure 6.6 with vertices at A(50,40), B(100,40), and C(75,200).

Figure 6.6. A 2D triangle to be rotated.

graphics/06fig06.gif

Solution
  1. Set up the matrix equation. The angle of rotation is 90°:

    graphics/06equ26.gif


  2. Now you have to plug in each old point and multiply the matrices to find the new location. First, plug in the old location of vertex A(50,40):

    graphics/06equ27.gif


    So A' is the point (–40,50).

  3. If you repeat step 2 with the old locations of B and C, you get the new locations B'(–40,100) and C'(–200,75). By rotating all three vertices, you have rotated the whole triangle. The original location and the new location are shown in Figure 6.7.

    Figure 6.7. A 2D triangle before and after rotation.

    graphics/06fig07.gif

Rotating objects in 2D is an important thing to be able to process. The calculations are pretty straightforward. Let's take a look at a function that rotates a 2D point:


Matrix3X1 rotate2D(Matrix3X1 start, float theta)

    {

         Matrix3X3 temp;

         Matrix3X1 result;

         //Zero out the matrix.

         temp = createFixed3X3Matrix(0);

         //place the needed rotational values into the matrix.

         temp.index[0][0] = cos(DegreesToRads(theta));

         temp.index[1][1] = cos(DegreesToRads(theta));

         temp.index[2][2] = 1;

         temp.index[0][1] = -1*(sin(DegreesToRads(theta)));

         temp.index[1][0] = sin(DegreesToRads(theta));

         temp.index[2][2] = 1;

         result = multiplyMatrixNxM(temp,start);

         return result;

    }

You can see we are using the DegreesToRads() macro that was referenced at the beginning of the chapter. Stepping through, we initialize the values of the rotation matrix based on the amount of rotation specified by the user. Once the matrix is set up, we can then just multiply the current matrix by the rotation matrix and we will have the newly translated points.

Here is some sample code that will allow us to translate a whole rectangle around a center point:


void rotate2D()

    {

         Matrix3X1 start,temp;

         float height,width,theta;

         cout<<"Let's rotate a 2D!\n";

         cout<<"Please enter the coordinates and dimensions.\n";

         cout<<"X coordinates\n";

         cin>>start.index[0];

         cout<<"Now the Y coordinate.\n";

         cin>>start.index[1];

         cout<<"Enter the rectangle's height.\n";

         cin>>height;

         cout<<"Enter the rectangle's width.\n";

         cin>>width;

         //make sure the last part of the matrix is a 1.

         start.index[2] = 1;

         cout<<endl;

         cout<<"Now enter the amount to rotate by in degrees.\n";

         cin>>theta;

         //Now that we have our info, lets rotate!

         temp = rotate2D(start,theta);



      //This gives the new locations calced from the temp matrix.

         width = temp.index[0]+width;

         height = temp.index[1]+height;



         cout<<"The right coordinate of the rectangle <<width<<","<<temp.index[1]<<"\n";

         cout<<"The bottom coordiante of the rectangle "<<height<<","<<temp.index[0]<<"\n";

    }

The main reason that rotation is so important with respect to this square is that most 2D images are represented in a square format, even if the alpha channel blocks out some of the colors from the user. It is common to use the current position to handle the display of graphics. This rotation algorithm lets the user specify what facing he wants a particular graphic to have. Some games will directly tie the input from the user to the facing and process the updates using a similar rotation algorithm.

In Figure 6.7, notice that the triangle rotated and moved. You might have expected it to stay in the same place and rotate. Unfortunately, that is also a combo.

NOTE

Again, this issue can be resolved by setting up a local origin for the model (also called its pivot).


By default, the rotation matrix rotates objects with respect to the origin, just like the scaling matrix does. The resulting effect is that the object appears to be orbiting about the origin. If you want the object to rotate about its own center or a particular vertex so that it appears to be tipping over, that is a combo, and we'll discuss that process in the next section.

In the meantime, let's take a look at 3D rotation. 2D has only one plane to rotate in, much like a flat screen. However, 3D has three different planes to rotate in—the xy plane, the yz plane, and the xz plane. These three planes are shown in Figure 6.8.

Figure 6.8. The three planes in 3D.

graphics/06fig08.gif

Notice that the xy plane is the same as the flat 2D plane you're used to working with for the computer screen. Because there are three separate planes to rotate within, there are three separate rotation matrices for 3D. Let's examine them one at a time.

3D Rotation About the Z-Axis (Roll)

graphics/06equ28.gif


where q is the angle of rotation.


Remember that the z-axis comes in and out of the screen, so if you rotate around the z-axis it's the same as rotating inside the flat screen (xy plane). That's why this rotation matrix looks almost the same as the 2D rotation matrix; it just has an extra row and column of identity to make it a 4x4 matrix. Notice also that this particular rotation is labeled roll. This name comes from flight simulator terminology. If you stand up with your arms extended to the side and bend from side to side, it's the same motion as a plane rolling.

To rotate around the z-axis, use the following function:


Matrix4X1 rotate3DZ(Matrix4X1 start, float theta)

    {

         Matrix4X4 temp;

         Matrix4X1 result;



         //Zero out the matrix.

         temp = createFixed4X4Matrix(0);



         //put the needed rotation values into the matrix from theta.

         temp.index[0][0] = cos(DegreesToRads(theta));

         temp.index[1][1] = cos(DegreesToRads(theta));

         temp.index[2][2] = 1;

         temp.index[3][3] = 1;



         temp.index[0][1] = -1*(sin(DegreesToRads(theta)));

         temp.index[1][0] = sin(DegreesToRads(theta));





         result = multiplyMatrixNxM(temp,start);

         return result;

    }

Make sure that when you are setting up your own rotation algorithms that you watch the radian calculations. Also make sure you put the values in the proper positions.

3D Rotation About the X-Axis (Pitch)

graphics/06equ28.gif


where q is the angle of rotation.


The x-axis runs left and right, so if you rotate around the x-axis, it's the same motion as standing up and bending over to take a bow.

In flight simulator terms, that's the same motion as pitching, so many programmers call rotation about the x-axis pitch. Notice the shift in the location of the sines and cosines. The first row and column typically represent x values, and in this case the first row and column have identity values. If you're rotating about the x-axis, the x-coordinates of the vertices shouldn't change, so that makes sense. This little trick might help you memorize the 3D rotation matrices. It works for rotating about the y- and z-axes as well.

Here's one way to rotate about the X-axis:


Matrix4X1 rotate3DX(Matrix4X1 start, float theta)

    {

         Matrix4X4 temp;

         Matrix4X1 result;



         //Zero out the matrix.

         temp = createFixed4X4Matrix(0);



         //place needed rotation values into the matrix based on theta.

         temp.index[0][0] = 1;

         temp.index[1][1] = cos(DegreesToRads(theta));

         temp.index[2][2] = cos(DegreesToRads(theta));

         temp.index[3][3] = 1;



         temp.index[1][2] = -1*(sin(DegreesToRads(theta)));

         temp.index[2][1] = sin(DegreesToRads(theta));





         result = multiplyMatrixNxM(temp,start);

         return result;

    }

The main changes here are the locations of the sine and cosine values of theta. This example is used in the sample source code provided for this chapter.

3D Rotation About the Y-Axis (Yaw)

graphics/06equ30.gif


where q is the angle of rotation.


Notice in this case that the second row and column (which represent y values) have identity values. Rotation about the y-axis in simulation terminology is the same as yaw. If you stand in place and spin around like a ballerina, that's the motion described as yaw. You can also visualize yaw by picturing someone spinning around a vertical pole. As soon as you have each matrix equation set up, all you have to do is plug in the original location of each vertex and multiply it to find the new location.

Unfortunately, these three types of rotation must be planned separately, but you'll see in the next section that they can eventually be combined.

Here's a function to rotate about the Y-axis:


Matrix4X1 rotate3DY(Matrix4X1 start, float theta)

    {

         Matrix4X4 temp;

         Matrix4X1 result;



         //Zero out the matrix.

         temp = createFixed4X4Matrix(0);



         //place the rotational values into the matrix based on theta.

         temp.index[0][0] = cos(DegreesToRads(theta));

         temp.index[1][1] = 1;

         temp.index[2][2] = cos(DegreesToRads(theta));

         temp.index[3][3] = 1;



         temp.index[2][0] = -1*(sin(DegreesToRads(theta)));

         temp.index[0][2] = sin(DegreesToRads(theta));





         result = multiplyMatrixNxM(temp,start);

         return result;

    }

Remember to double-check the locations of the sine and cosine values.

NOTE

These three rotation matrices are also designed to rotate with respect to the origin, so they all have the same orbiting effect as the 2D rotation matrix. Again, if you want to rotate with respect to another point, that has to be set up as a combo.


Example 6.10: 3D Rotation About the Y-Axis

Set up a general matrix equation that will rotate 3D objects pR about the y-axis, and then use it to rotate a triangle with vertices at A(100,0,–50), B(40,–30,0), and C(–20,100,50).

Solution
  1. Set up the matrix equation. The angle of rotation is pR or 180° (see Chapter 3 for the conversion):

    graphics/06equ31.gif


  2. Now you have to plug in each old point and multiply the matrices to find the new location. First, plug in the old location of vertex A(100,0,–50):

    graphics/06equ32.gif


    So A' is the point (–100,0,50).

  3. If you repeat step 2 with the old locations of B and C, you get the new locations B'(–40,–30,0) and C'(20,100,–50). By rotating all three vertices, you have rotated the whole triangle.

If you can rotate about the y-axis, you can rotate about the other two axes as well. They all work the same way. Notice that the examples use multiples of 90°, so the sines and cosines are all 0s and 1s. However, be aware that for other angles, the sines and cosines have decimal numbers, so the new locations aren't always nice whole numbers. Also, remember that all rotation matrices are set up for rotation about the origin. The next section discusses how to rotate with respect to any other point.

The functions from last chapter that were used to create random matrices are a good way to test the matrix multiplications. You should also give the user a way to enter manual values as well. Check the sample source code for this chapter to see 3D rotation around each axis in action.

Self-Assessment

1.

Set up a general matrix equation that will rotate 2D objects 30°, and then use it to rotate a triangle with vertices at A(–10,50), B(80,0), and C(–50,100).

2.

Set up a general matrix equation that will make 3D objects stand in place and rotate 1 degree at a time (about the y-axis), and then use it to rotate a triangle with vertices at D(0,20,–50), E(–10,0,20), and F(30,20,0).

3.

Set up a general matrix equation that will make 3D objects pitch 45°, and then use it to rotate a triangle with vertices at G(0,30,–100), H(–50,100,–20), and J(–20,0,–300).

4.

Set up a general matrix equation that will rotate 3D objects (p/2)R about the z-axis, and then use it to rotate a triangle with vertices at L(0,30,–100), M(–50,100,–20), and N(–20,0,–300).


    Previous Section  < Day Day Up >  Next Section