Previous | Table of Contents | Next

With the above optimizations, the sample program is certainly adequately responsive on a 20 MHz 386 (sans 387; I’m sure it’s wonderfully responsive with a math coprocessor). Still, it couldn’t quite keep up with the keyboard when I modified it to read only one key each time through the loop—and we’re talking about only eight vertices here. This indicates that we’re already near the limit of animation complexity possible with our current approach. It’s time to start rethinking that approach; over two-thirds of the overall time is spent in floating-point calculations, and it’s there that we’ll begin to attack the performance bottleneck we find ourselves up against.

### Incremental Transformation

Listing 51.4 contains three functions; each concatenates an additional rotation around one of the three axes to an existing rotation. To improve performance, only the matrix entries that are affected in a rotation around each particular axis are recalculated (all but four of the entries in a single-axis rotation matrix are either 0 or 1, as shown in Chapter 50). This cuts the number of floating-point multiplies from the 64 required for the multiplication of two 4×4 matrices to just 12, and floating point adds from 48 to 6.

Be aware that Listing 51.4 performs an incremental rotation on top of whatever rotation is already in the matrix. The cube may already have been turned left, right, up, down, and sideways; regardless, Listing 51.4 just tacks the specified rotation onto whatever already exists. In this way, the object-to-world transformation matrix contains a history of all the rotations ever specified by the user, concatenated one after another onto the original matrix. Potential loss of precision is a problem associated with using such an approach to represent a very long concatenation of transformations, especially with fixed-point arithmetic; that’s not a problem for us yet, but we’ll run into it eventually.

LISTING 51.4 L51-4.C

    /* Routines to perform incremental rotations around the three axes */
    #include <math.h>
    #include “polygon.h”

    /* Concatenate a rotation by Angle around the X axis to the transformation in
       XformToChange, placing result back in XformToChange. */
       void AppendRotationX(double XformToChange[4][4], double Angle)
    {
       double Temp10, Temp11, Temp12, Temp20, Temp21, Temp22;
       double CosTemp = cos(Angle), SinTemp = sin(Angle);
       /* Calculate the new values of the four affected matrix entries */
       Temp10 = CosTemp*XformToChange[1][0]+ -SinTemp*XformToChange[2][0];
       Temp11 = CosTemp*XformToChange[1][1]+ -SinTemp*XformToChange[2][1];
       Temp12 = CosTemp*XformToChange[1][2]+ -SinTemp*XformToChange[2][2];
       Temp20 = SinTemp*XformToChange[1][0]+ CosTemp*XformToChange[2][0];
       Temp21 = SinTemp*XformToChange[1][1]+ CosTemp*XformToChange[2][1];
       Temp22 = SinTemp*XformToChange[1][2]+ CosTemp*XformToChange[2][2];
       /* Put the results back into XformToChange */
       XformToChange[1][0] = Temp10; XformToChange[1][1] = Temp11;
       XformToChange[1][2] = Temp12; XformToChange[2][0] = Temp20;
       XformToChange[2][1] = Temp21; XformToChange[2][2] = Temp22;
    }

    /* Concatenate a rotation by Angle around the Y axis to the transformation in
       XformToChange, placing result back in XformToChange. */
       void AppendRotationY(double XformToChange[4][4], double Angle)
    {
       double Temp00, Temp01, Temp02, Temp20, Temp21, Temp22;
       double CosTemp = cos(Angle), SinTemp = sin(Angle);

       /* Calculate the new values of the four affected matrix entries */
       Temp00 = CosTemp*XformToChange[0][0]+ SinTemp*XformToChange[2][0];
       Temp01 = CosTemp*XformToChange[0][1]+ SinTemp*XformToChange[2][1];
       Temp02 = CosTemp*XformToChange[0][2]+ SinTemp*XformToChange[2][2];
       Temp20 = -SinTemp*XformToChange[0][0]+ CosTemp*XformToChange[2][0];
       Temp21 = -SinTemp*XformToChange[0][1]+ CosTemp*XformToChange[2][1];
       Temp22 = -SinTemp*XformToChange[0][2]+ CosTemp*XformToChange[2][2];
       /* Put the results back into XformToChange */
       XformToChange[0][0] = Temp00; XformToChange[0][1] = Temp01;
       XformToChange[0][2] = Temp02; XformToChange[2][0] = Temp20;
       XformToChange[2][1] = Temp21; XformToChange[2][2] = Temp22;
    }

    /* Concatenate a rotation by Angle around the Z axis to the transformation in
       XformToChange, placing result back in XformToChange. */
       void AppendRotationZ(double XformToChange[4][4], double Angle)
    {
       double Temp00, Temp01, Temp02, Temp10, Temp11, Temp12;
       double CosTemp = cos(Angle), SinTemp = sin(Angle);
       /* Calculate the new values of the four affected matrix entries */
       Temp00 = CosTemp*XformToChange[0][0]+ -SinTemp*XformToChange[1][0];
       Temp01 = CosTemp*XformToChange[0][1]+ -SinTemp*XformToChange[1][1];
       Temp02 = CosTemp*XformToChange[0][2]+ -SinTemp*XformToChange[1][2];
       Temp10 = SinTemp*XformToChange[0][0]+ CosTemp*XformToChange[1][0];
       Temp11 = SinTemp*XformToChange[0][1]+ CosTemp*XformToChange[1][1];
       Temp12 = SinTemp*XformToChange[0][2]+ CosTemp*XformToChange[1][2];
       /* Put the results back into XformToChange */
       XformToChange[0][0] = Temp00; XformToChange[0][1] = Temp01;
       XformToChange[0][2] = Temp02; XformToChange[1][0] = Temp10;
       XformToChange[1][1] = Temp11; XformToChange[1][2] = Temp12;
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash