The Mathematics of the 3D Rotation Matrix: Source Code

The Mathematics of the 3D Rotation Matrix: Source Code

Diana Gruber

Note: This is NOT THE SOURCE CODE TO FASTGRAPH. This is just some C++ code I wrote over the weekend to illustrate the ideas in my paper The Mathematics of the 3D Rotation Matrix. You may use this code however you see fit.

Recently I have been benchmarking this code against Fastgraph. Fastgraph is written in assembly language, and takes advantage of the speed boost available using concurrent floating point operations. Vectors consist of 3 floats. A floating point operation takes 3 cycles. You can start two more operations before the first one finishes. So you can do 3 floating point operations at the same time. Get it?

So far, Fastgraph beats this code by 200%-500%, depending on such things as what compiler switches you apply. There are further optimizations that can be applied to this C++ code. In many cases you don't need to do a complete matrix multiply, for example. Since the first 3 columns of the transform matrix are identical to the rotation matrix, you can take a shortcut and just calculate the 4th column.

Source code here is presented "as is". Use it at your own risk. Please report any errors to dgruber@fastgraph.com. Don't flame me, just report the errors.


//---------------------------------------------------------------------------
/* 3D.h: declarations for 3D rotation/translation class 3D.cpp */

#ifndef _3DH
#define _3DH

//---------------------------------------------------------------------------
class _3D
{
private:

   // internal vectors and matrices
   double WorldUp[3];
   double ViewMoveMatrix[12];
   double ViewRotationMatrix[12];
   double WorldTransform[12];
   double ObjectMoveMatrix[12];
   double ObjectRotationMatrix[12];
   double ObjectTransform[12];
   double CombinedTransform[12];

   // helper functions
   void MatrixMultiply(double *A, double *B, double *C);
   void MoveFill(double *A, double Cx, double Cy, double Cz);
   void RotateFill(double *A, double Cx, double Cy, double Cz);

public:
 
   double pi;

   _3D(void); // constructor

   // 3D functions
   void _3DAxisAngle (double x, double y, double z, double theta);
   void _3DAxisAngleObject (double x, double y, double z, double theta);
   void _3DGetView (double *x1, double *y1, double *z1, double *x2, double *y2, double *z2);
   int  _3DLookAt (double x1, double y1, double z1, double x2, double y2, double z2);
   void _3DPOV(double Cx, double Cy, double Cz, double xAngle, double yAngle, double zAngle);
   void _3DRoll(double theta);
   void _3DRollObject(double theta);
   void _3DRotateRight(double theta);
   void _3DRotateRightObject(double theta);
   void _3DRotateUp(double theta);
   void _3DRotateUpObject(double theta);
   void _3DMove(double x, double y, double z);
   void _3DMoveObject(double x, double y, double z);
   void _3DMoveForward(double n);
   void _3DMoveForwardObject(double n);
   void _3DMoveRight(double n);
   void _3DMoveRightObject(double n);
   void _3DMoveUp(double n);
   void _3DMoveUpObject(double n);
   void _3DSetObject(double Ox, double Oy, double Oz, int xAngle, int yAngle, int zAngle);
   void _3DUpVector(double x, double y, double z);
};
#endif

/*

            Absolute Moves
            --------------
View                             Object
----                             ------
_3DMove()                        _3DMoveObject


            Relative Moves
            --------------
View                             Object
----                             ------
 _3DMoveForward()                _3DMoveForwardObject()
 _3DMoveRight()                  _3DMoveRightObject()
 _3DMoveUp()                     _3DMoveUpObject()


            Absolute Rotations
            ------------------
View                             Object
----                             ------
_3DAxis/Angle()                  _3DAxis/AngleObject()


            Relative Rotations (roll, pitch, yaw)
            -------------------------------------
View                             Object
----                             ------
_3DRoll()                        _3DRollObject()
_3DRotateRight()                 _3DRotateRightObject()
_3DRotateUp()                    _3DRotateUpObject


            Absolute Move + Absolute Rotation using Euler Angles
            -----------------------------------------
View                             Object
----                             ------
_3DPOV()                         _3DSetObject()


            Absolute Move + Absolute Rotation using Look At vector
            -----------------------------------------
View                             Object
----                             ------
_3DLookAt()                       ?

*/


/* --------------------------------------------------------------------------
3D.CPP by Diana Gruber

This is the code I wrote to illustrate some of the ideas I had about
3D rotation. This is NOT THE SOURCE CODE TO FASTGRAPH. Fastgraph is
written in assembly language. It is much faster than this C++ code.

This code illustrates the concepts in my paper "The Mathematics of the 
3D Rotation Matrix" presented at XGDC on October 1, 2000. Hopefully
you will find it easy to follow and mildly interesting. If you are
looking at this in hard copy and you want to download it, try
http://www.makegames.com/3Drotation or email me at dgruber@fastgraph.com.

-------------------------------------------------------------------------- */
#include "3D.h"
#include 
#include 

//---------------------------------------------------------------------------
_3D::_3D(void)
{
   /* Constructor -- initialize */

   // initialize WorldUp
   WorldUp[0] = 0;
   WorldUp[1] = 1.0;
   WorldUp[2] = 0;

   // initialize the World Transform
   _3DPOV(0,0,0,0,0,0);

   // initialize the Object Transform
   _3DSetObject(0,0,0,0,0,0);

   // calculate a value for pi
   pi = 4.0*atan(1.0);
}

//---------------------------------------------------------------------------
void _3D::_3DAxisAngle (double x, double y, double z, double theta)
{
   /* This function performs an axis/angle rotation. (x,y,z) is any 
      vector on the axis. For greater speed, always use a unit vector 
      (length = 1). In this version, we will assume an arbitrary 
      length and normalize. */

   double length;
   double c,s,t;

   // normalize
   length = sqrt(x*x + y*y + z*z);

   // too close to 0, can't make a normalized vector
   if (length < .000001)
      return;

   x /= length;
   y /= length;
   z /= length;

   // do the trig
   c = cos(theta);
   s = sin(theta);
   t = 1-c;   

   // build the rotation matrix
   ViewRotationMatrix[0] = t*x*x + c;
   ViewRotationMatrix[1] = t*x*y - s*z;
   ViewRotationMatrix[2] = t*x*z + s*y;
   ViewRotationMatrix[3] = 0;

   ViewRotationMatrix[4] = t*x*y + s*z;
   ViewRotationMatrix[5] = t*y*y + c;
   ViewRotationMatrix[6] = t*y*z - s*x;
   ViewRotationMatrix[7] = 0;

   ViewRotationMatrix[8] = t*x*z - s*y;
   ViewRotationMatrix[9] = t*y*z + s*x;
   ViewRotationMatrix[10] = t*z*z + c;
   ViewRotationMatrix[11] = 0;

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DAxisAngleObject (double x, double y, double z, double theta)
{
   /* This function performs an axis/angle rotation. (x,y,z) is any 
      vector on the axis. For greater speed, always use a unit vector 
      (length = 1). In this version, we will assume an arbitrary 
      length and normalize. */

   double length;
   double c,s,t;

   // normalize
   length = sqrt(x*x + y*y + z*z);

   // too close to 0, can't make a normalized vector
   if (length < .000001)
      return;

   x /= length;
   y /= length;
   z /= length;

   // do the trig
   c = cos(theta);
   s = sin(theta);
   t = 1-c;   

   // build the rotation matrix
   ObjectRotationMatrix[0] = t*x*x + c;
   ObjectRotationMatrix[1] = t*x*y - s*z;
   ObjectRotationMatrix[2] = t*x*z + s*y;
   ObjectRotationMatrix[3] = 0;

   ObjectRotationMatrix[4] = t*x*y + s*z;
   ObjectRotationMatrix[5] = t*y*y + c;
   ObjectRotationMatrix[6] = t*y*z - s*x;
   ObjectRotationMatrix[7] = 0;

   ObjectRotationMatrix[8] = t*x*z - s*y;
   ObjectRotationMatrix[9] = t*y*z + s*x;
   ObjectRotationMatrix[10] = t*z*z + c;
   ObjectRotationMatrix[11] = 0;

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DGetView (double *x1, double *y1, double *z1, double *x2, double *y2, double *z2)
{
   /* Returns the current position and a unit vector representing
      the direction of the rotation */

   // the current position is the 4th column of the translation matrix
   *x1 = -ViewMoveMatrix[3];
   *y1 = -ViewMoveMatrix[7];
   *z1 = -ViewMoveMatrix[11];

   // the "out" unit vector is the 3rd row of the rotation matrix
   *x2 = ViewRotationMatrix[8];
   *y2 = ViewRotationMatrix[9];
   *z2 = ViewRotationMatrix[10];
}

//---------------------------------------------------------------------------
int _3D::_3DLookAt (double x1, double y1, double z1, double x2, double y2, double z2)
{
   /* Build a transform as if you were at a point (x1,y1,z1), and
      looking at a point (x2,y2,z2) */

   double ViewOut[3];      // the View or "new Z" vector
   double ViewUp[3];       // the Up or "new Y" vector
   double ViewRight[3];    // the Right or "new X" vector

   double ViewMagnitude;   // for normalizing the View vector
   double UpMagnitude;     // for normalizing the Up vector
   double UpProjection;    // magnitude of projection of View Vector on World UP

   // first, calculate and normalize the view vector
   ViewOut[0] = x2-x1;
   ViewOut[1] = y2-y1;
   ViewOut[2] = z2-z1;
   ViewMagnitude = sqrt(ViewOut[0]*ViewOut[0] + ViewOut[1]*ViewOut[1]+
      ViewOut[2]*ViewOut[2]);

   // invalid points (not far enough apart)
   if (ViewMagnitude < .000001)
      return (-1);

   // normalize. This is the unit vector in the "new Z" direction
   ViewOut[0] = ViewOut[0]/ViewMagnitude;
   ViewOut[1] = ViewOut[1]/ViewMagnitude;
   ViewOut[2] = ViewOut[2]/ViewMagnitude;

   // Now the hard part: The ViewUp or "new Y" vector

   // dot product of ViewOut vector and World Up vector gives projection of
   // of ViewOut on WorldUp
   UpProjection = ViewOut[0]*WorldUp[0] + ViewOut[1]*WorldUp[1]+
   ViewOut[2]*WorldUp[2];

   // first try at making a View Up vector: use World Up
   ViewUp[0] = WorldUp[0] - UpProjection*ViewOut[0];
   ViewUp[1] = WorldUp[1] - UpProjection*ViewOut[1];
   ViewUp[2] = WorldUp[2] - UpProjection*ViewOut[2];

   // Check for validity:
   UpMagnitude = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2];

   if (UpMagnitude < .0000001)
   {
      //Second try at making a View Up vector: Use Y axis default  (0,1,0)
      ViewUp[0] = -ViewOut[1]*ViewOut[0];
      ViewUp[1] = 1-ViewOut[1]*ViewOut[1];
      ViewUp[2] = -ViewOut[1]*ViewOut[2];

      // Check for validity:
      UpMagnitude = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2];

      if (UpMagnitude < .0000001)
      {
          //Final try at making a View Up vector: Use Z axis default  (0,0,1)
          ViewUp[0] = -ViewOut[2]*ViewOut[0];
          ViewUp[1] = -ViewOut[2]*ViewOut[1];
          ViewUp[2] = 1-ViewOut[2]*ViewOut[2];

          // Check for validity:
          UpMagnitude = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2];

          if (UpMagnitude < .0000001)
              return(-1);
      }
   }

   // normalize the Up Vector
   UpMagnitude = sqrt(UpMagnitude);
   ViewUp[0] = ViewUp[0]/UpMagnitude;
   ViewUp[1] = ViewUp[1]/UpMagnitude;
   ViewUp[2] = ViewUp[2]/UpMagnitude;

   // Calculate the Right Vector. Use cross product of Out and Up.
   ViewRight[0] = -ViewOut[1]*ViewUp[2] + ViewOut[2]*ViewUp[1];
   ViewRight[1] = -ViewOut[2]*ViewUp[0] + ViewOut[0]*ViewUp[2];
   ViewRight[2] = -ViewOut[0]*ViewUp[1] + ViewOut[1]*ViewUp[0];

   // Plug values into rotation matrix R
   ViewRotationMatrix[0]=ViewRight[0];
   ViewRotationMatrix[1]=ViewRight[1];
   ViewRotationMatrix[2]=ViewRight[2];
   ViewRotationMatrix[3]=0;

   ViewRotationMatrix[4]=ViewUp[0];
   ViewRotationMatrix[5]=ViewUp[1];
   ViewRotationMatrix[6]=ViewUp[2];
   ViewRotationMatrix[7]=0;

   ViewRotationMatrix[8]=ViewOut[0];
   ViewRotationMatrix[9]=ViewOut[1];
   ViewRotationMatrix[10]=ViewOut[2];
   ViewRotationMatrix[11]=0;

   // Plug values into translation matrix T
   MoveFill(ViewMoveMatrix,-x1,-y1,-z1);

   // build the World Transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);

   return(0);
}

//---------------------------------------------------------------------------
void _3D::_3DMove(double x, double y, double z)
{
   /* Absolute move, without changing the rotation */

   ViewMoveMatrix[3] = -x;
   ViewMoveMatrix[7] = -y;
   ViewMoveMatrix[11]= -z;

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveObject(double x, double y, double z)
{
   /* Absolute move, without changing the rotation */

   ObjectMoveMatrix[3] = x;
   ObjectMoveMatrix[7] = y;
   ObjectMoveMatrix[11]= z;

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveForward(double n)
{
   /* Take the 3rd row of the rotation matrix, multiply by a constant
      and add to the translation vector */

   ViewMoveMatrix[3] = ViewMoveMatrix[3] - n*ViewRotationMatrix[8];
   ViewMoveMatrix[7] = ViewMoveMatrix[7] - n*ViewRotationMatrix[9];
   ViewMoveMatrix[11]= ViewMoveMatrix[11]- n*ViewRotationMatrix[10];

   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveForwardObject(double n)
{
   /* Take the 3rd row of the rotation matrix, multiply by a constant
      and add to the translation vector */

   ObjectMoveMatrix[3] = ObjectMoveMatrix[3] - n*ObjectRotationMatrix[8];
   ObjectMoveMatrix[7] = ObjectMoveMatrix[7] - n*ObjectRotationMatrix[9];
   ObjectMoveMatrix[11]= ObjectMoveMatrix[11]- n*ObjectRotationMatrix[10];

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveRight(double n)
{
   /* Take the 1st row of the rotation matrix, multiply by a constant
      and add to the translation vector */

   ViewMoveMatrix[3] = ViewMoveMatrix[3] - n*ViewRotationMatrix[0];
   ViewMoveMatrix[7] = ViewMoveMatrix[7] - n*ViewRotationMatrix[1];
   ViewMoveMatrix[11]= ViewMoveMatrix[11]- n*ViewRotationMatrix[2];

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveRightObject(double n)
{
   /* Take the 1st row of the rotation matrix, multiply by a constant
      and add to the translation vector */

   ObjectMoveMatrix[3] = ObjectMoveMatrix[3] - n*ObjectRotationMatrix[0];
   ObjectMoveMatrix[7] = ObjectMoveMatrix[7] - n*ObjectRotationMatrix[1];
   ObjectMoveMatrix[11]= ObjectMoveMatrix[11]- n*ObjectRotationMatrix[2];

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveUp(double n)
{
   /* Take the 2nd row of the rotation matrix, multiply by a 
      constant and add to the translation vector */

   ViewMoveMatrix[3] = ViewMoveMatrix[3] - n*ViewRotationMatrix[4];
   ViewMoveMatrix[7] = ViewMoveMatrix[7] - n*ViewRotationMatrix[5];
   ViewMoveMatrix[11]= ViewMoveMatrix[11]- n*ViewRotationMatrix[6];

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DMoveUpObject(double n)
{
   /* Take the 2nd row of the rotation matrix, multiply by a 
      constant and add to the translation vector */

   ObjectMoveMatrix[3] = ObjectMoveMatrix[3] - n*ObjectRotationMatrix[4];
   ObjectMoveMatrix[7] = ObjectMoveMatrix[7] - n*ObjectRotationMatrix[5];
   ObjectMoveMatrix[11]= ObjectMoveMatrix[11]- n*ObjectRotationMatrix[6];

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DPOV(double Cx, double Cy, double Cz, double xAngle, double yAngle, double zAngle)
{
   /* Set the Point of View (World Transform) using Euler Angles.
      This is the simplest but least useful way to do a 3D rotation,
      and is subject to gimbal lock. */

   // Fill translation matrix
   MoveFill(ViewMoveMatrix,-Cx,-Cy,-Cz);

   // Fill rotation matrix
   RotateFill(ViewRotationMatrix,xAngle,yAngle,zAngle);

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRoll(double theta)
{
   /* Multiply the rotation matrix with a rotation around Out
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(-theta);
   s = sin(-theta);

   R[0] = c;    R[1] = -s;   R[2] = 0;   R[3] = 0;
   R[4] = s;    R[5] = c;    R[6] = 0;   R[7] = 0;
   R[8] = 0;    R[9] = 0;    R[10]= 1;   R[11]= 0;

   MatrixMultiply(R,ViewRotationMatrix,W);
   memcpy(ViewRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRollObject(double theta)
{
   /* Multiply the rotation matrix with a rotation around Out
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(-theta);
   s = sin(-theta);

   R[0] = c;    R[1] = -s;   R[2] = 0;   R[3] = 0;
   R[4] = s;    R[5] = c;    R[6] = 0;   R[7] = 0;
   R[8] = 0;    R[9] = 0;    R[10]= 1;   R[11]= 0;

   MatrixMultiply(R,ObjectRotationMatrix,W);
   memcpy(ObjectRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRotateRight(double theta)
{
   /* Multiply the rotation matrix with a rotation around Up
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(-theta);
   s = sin(-theta);

   R[0] = c;   R[1] = 0;   R[2] = s;   R[3] = 0;
   R[4] = 0;   R[5] = 1;   R[6] = 0;   R[7] = 0;
   R[8] = -s;  R[9] = 0;   R[10]= c;   R[11]= 0;

   MatrixMultiply(R,ViewRotationMatrix,W);
   memcpy(ViewRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRotateRightObject(double theta)
{
   /* Multiply the rotation matrix with a rotation around Up
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(-theta);
   s = sin(-theta);

   R[0] = c;   R[1] = 0;   R[2] = s;   R[3] = 0;
   R[4] = 0;   R[5] = 1;   R[6] = 0;   R[7] = 0;
   R[8] = -s;  R[9] = 0;   R[10]= c;   R[11]= 0;

   MatrixMultiply(R,ObjectRotationMatrix,W);
   memcpy(ObjectRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRotateUp(double theta)
{
   /* Multiply the rotation matrix with a rotation around Right
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(theta);
   s = sin(theta);

   R[0] = 1;   R[1] = 0;   R[2] = 0;   R[3] = 0;
   R[4] = 0;   R[5] = c;   R[6] = -s;  R[7] = 0;
   R[8] = 0;   R[9] = s;   R[10]= c;   R[11]= 0;

   MatrixMultiply(R,ViewRotationMatrix,W);
   memcpy(ViewRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ViewRotationMatrix,ViewMoveMatrix,WorldTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DRotateUpObject(double theta)
{
   /* Multiply the rotation matrix with a rotation around Right
      to get a new rotation matrix. */

   double R[12];
   double W[12];
   double c,s;

   c = cos(theta);
   s = sin(theta);

   R[0] = 1;   R[1] = 0;   R[2] = 0;   R[3] = 0;
   R[4] = 0;   R[5] = c;   R[6] = -s;  R[7] = 0;
   R[8] = 0;   R[9] = s;   R[10]= c;   R[11]= 0;

   MatrixMultiply(R,ObjectRotationMatrix,W);
   memcpy(ObjectRotationMatrix,W,12*sizeof(double));

   // build the transform
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DSetObject(double Ox, double Oy, double Oz, int xAngle, int yAngle, int zAngle)
{
   /* The object transform is used to move and rotate objects. It
      uses Euler angles. */

   // set item translation matrix
   MoveFill(ObjectMoveMatrix,Ox,Oy,Oz);

   // set item rotation matrix
   RotateFill(ObjectRotationMatrix,xAngle,yAngle,zAngle);

   // note order is OPPOSITE from world transform: move first!
   MatrixMultiply(ObjectMoveMatrix,ObjectRotationMatrix,ObjectTransform);

   // concatenate with the world transform
   MatrixMultiply(WorldTransform,ObjectTransform,CombinedTransform);
}

//---------------------------------------------------------------------------
void _3D::_3DUpVector(double x, double y, double z)
{
   /* Change the World Up vector (the default is (0,1,0))
      For greater speed you can normalize and verify here 
      instead of in _3DLookAt() */

   WorldUp[0] = x;
   WorldUp[1] = y;
   WorldUp[2] = z;
}

//---------------------------------------------------------------------------
/* The following are the "helper" functions */
//---------------------------------------------------------------------------
void _3D::MatrixMultiply(double *A, double *B, double *C)
{
   /* A matrix multiplication (dot product) of two 4x4 matrices.
      Actually, we are only using matrices with 3 rows and 4 columns. */

   C[0] = A[0]*B[0] + A[1]*B[4] + A[2]*B[8];
   C[1] = A[0]*B[1] + A[1]*B[5] + A[2]*B[9];
   C[2] = A[0]*B[2] + A[1]*B[6] + A[2]*B[10];
   C[3] = A[0]*B[3] + A[1]*B[7] + A[2]*B[11] + A[3];

   C[4] = A[4]*B[0] + A[5]*B[4] + A[6]*B[8];
   C[5] = A[4]*B[1] + A[5]*B[5] + A[6]*B[9];
   C[6] = A[4]*B[2] + A[5]*B[6] + A[6]*B[10];
   C[7] = A[4]*B[3] + A[5]*B[7] + A[6]*B[11] + A[7];

   C[8] = A[8]*B[0] + A[9]*B[4] + A[10]*B[8];
   C[9] = A[8]*B[1] + A[9]*B[5] + A[10]*B[9];
   C[10] = A[8]*B[2] + A[9]*B[6] + A[10]*B[10];
   C[11] = A[8]*B[3] + A[9]*B[7] + A[10]*B[11] + A[11];
}

//---------------------------------------------------------------------------
void _3D::MoveFill(double *A, double Cx, double Cy, double Cz)
{
   /* Fill the translation matrix */

   A[0] = 1;   A[1] = 0;   A[2] = 0;   A[3] = Cx;
   A[4] = 0;   A[5] = 1;   A[6] = 0;   A[7] = Cy;
   A[8] = 0;   A[9] = 0;   A[10]= 1;   A[11]= Cz;
}

//---------------------------------------------------------------------------
void _3D::RotateFill(double *A, double xAngle, double yAngle, double zAngle)
{
   /* Fill the rotation matrix, using Euler angles */

   double x[12];
   double y[12];
   double z[12];
   double tempArray[12];
   double cx,cy,cz;
   double sx,sy,sz;

   cx = cos(xAngle);
   cy = cos(yAngle);
   cz = cos(zAngle);

   sx = sin(xAngle);
   sy = sin(yAngle);
   sz = sin(zAngle);

   x[0]=1;     x[1]=0;     x[2] =0;     x[3] =0;
   x[4]=0;     x[5]=cx;    x[6] =-sx;   x[7] =0;
   x[8]=0;     x[9]=sx;    x[10]=cx;    x[11]=0;

   y[0]=cy;    y[1]=0;     y[2] =sy;    y[3] =0;
   y[4]=0;     y[5]=1;     y[6] =0;     y[7] =0;
   y[8]=-sy;   y[9]=0;     y[10]=cy;    y[11]=0;

   z[0]=cz;    z[1]=-sz;   z[2] =0;     z[3] =0;
   z[4]=sz;    z[5]=cz;    z[6] =0;     z[7] =0;
   z[8]=0;     z[9]=0;     z[10]=1;     z[11]=0;

   /* Note we are multiplying x*y*z. You can change the order,
      but you will get different results. */

   MatrixMultiply(z,y,tempArray);   // multiply 2 matrices
   MatrixMultiply(tempArray,x,A);   // multiply result by 3rd matrix
}


 

Copyright © 2000 Ted Gruber Software, Inc. All rights reserved.