Quaternions here I come

I’m not even going to try to pretend I understand the math theory behind quaternions, but after failing miserably to implement my spaceship rotation with Euler yaw, pitch, roll, I figured quaternions are what I need to use.

So far I’ve seen GameDev.net’s explaination and code. http://www.gamedev.net/reference/articles/article1095.asp

I’m not a math genius but his algorthim seems reasonable to me. I just would like a second opinion. Anybody out there have a favorite Quaternion “technique” they like to use?

For my situation I have a spaceship that I need to keep track of its orientation for when the player hits the thrusters and I allow yaw, pitch, and roll rotations on the spaceship.

I recommend making a matrix class to handle transformations such as quaternion rotation. If not a class, then at least make a group of functions that can make various types of transformation matrices. You’ll also want to have a mechanism for multiplying matrices together and multiplying matrices by points (and vectors). It sounds like a lot of work, but it will save you a lot of time when you can do:

Matrix matrix;
Point3D point;


and also:


Here is my function that makes a rotation matrix from an angle and axis.

void Matrix::MakeQuaternionAA(double a, double x, double y, double z)
double rad = (double)(3.141592654*(double)a/(double)180);

double sin_a = (double)sin( rad / 2 );   
double cos_a = (double)cos( rad / 2 );

double qx = x * sin_a;   
double qy = y * sin_a;
double qz = z * sin_a;
double qw = cos_a;

double mag = (double)sqrt(qw*qw + qx*qx + qy*qy + qz*qz) ;
qx /= mag;
qy /= mag;
qz /= mag;
qw /= mag;

double xx      = qx * qx;
double xy      = qx * qy;    
double xz      = qx * qz;   
double xw      = qx * qw;
double yy      = qy * qy;   
double yz      = qy * qz;    
double yw      = qy * qw;   
double zz      = qz * qz;
double zw      = qz * qw;

mdata[0]=1-2*(yy-zz); mdata[4]= 2*(xy-zw);   mdata[8]=2*(xz+yw);    mdata [12] = 0;
mdata[1]=2*(xy+zw);   mdata[5]= 1-2*(xx-zz); mdata[9]=2*(yz-xw);    mdata [13] = 0;
mdata[2]=2*(xz-yw);   mdata[6]= 2*(yz+xw);   mdata[10]=1-2*(xx-yy); mdata [14] = 0;
mdata[3]=0;           mdata[7]= 0;           mdata[11]=0;	        mdata [15] = 1;


You then multiply a point by the matrix to rotate it, or use glMultMatrixd(matrix.mdata) to modify the modelview matrix.

One more thing. For all my objects, I store the local up, right, and forward vectors. This allows me to preserve the object’s axes. For instance, to make an airplane roll about it’s own axes, I would use the above function like this matrix.MakeQuaternionAA(rollangle, object.forwardvector.x, object.forwardvector.y, object.forwardvector.z). Then I multiply the upvector and rightvector by that matrix to get the new orientation of the object.

Hope this helps.

[This message has been edited by ioquan (edited 07-07-2002).]

What you said about keeping the forward, up, and right vectors for each object really hit me as something I myself am going to have to do. If I were to try do everything by just storing yaw, pitch, and roll I would have to calculate a forward vector anyway so I could do the physics of my spaceship’s thruster with its current velocity.

But you said you multiply the up, forward, and right vectors by the rotation matrix and that makes me wonder. Would these vectors start drifting so they are no longer orthonormal to each other? Do you have to take the cross product of these vectors to make sure they are orthonormal?

Anyways I’ve been struggling with how I’m going to do this all day, and your response certainly gave me some ideas.

Yes, there is a problem with them becoming non-orthogonal, and yes, you use the cross product to fix it.

You pick two of the vectors, and take the cross product. That will give you the third vector. Once you have the third, you take the cross product of it and one of the first two to get the other one. Doing this every frame (or whenever you change them) keeps them orthogonal.

There’s another advantage to storing your orientations this way that I didnt mention above. Since you have the three vectors, you can make a matrix with the vectors making up the 3x3 part. You can use glMultMatrixd with this matrix and it will orient your object! You can also put the object’s origin in the fourth row of the matrix, and that will translate the object all at once. You will no longer need glTranslate or glRotate.

[This message has been edited by ioquan (edited 07-07-2002).]

I’m pretty sure http://www.gametutorials.com has a couple tutorials that might help if you’re having problems.


if you go to the kalman filter example in the c code. This has loads of vector, quaternian and matrix operations.

here is a great resource for making rotation matrices. the easiest method shown involves creating a rotation matrix from an arbitrary axis and angle (similar to ioquan’s function). a vector multiplied by this matrix will be rotated around the axis by the angle. very helpful.


[This message has been edited by coredump (edited 07-08-2002).]

I also thought this http://www.psychology.nottingham.ac.uk/staff/cr1/3d.html was an interesting site.

Good luck.

Okay I’ve successfully coded an axis rotation using ioquan’s algorithm. I even calculated the forward, up, right unit vectors and combined that into a glmodelviewmatrix with the location of the model to do the complete transformation(rotation + translation) for the model. It works great. However, I am taking input from the user and they might be wanting to do a forward axis rotation and a up axis rotation and a right axis rotation all together. I implemented this using ioquan’s algorithm 3 times to calckulated the forward, up, right vectors for my transformation matrix I send to OGL.

Question: Is this the correct way to combine axis rotations? Is there a better way? Note: I am not storing the total Yaw, pitch, and roll angles of the model. I only store the current forward, up, right vectors.

I’m not exactly sure how you’re doing it, but it sounds pretty close to what I do. My objects have angular velocities - one value each for roll, pitch, and yaw. I rotate the object around each of it’s 3 local axes by those values. Then I adjust the vectors to make them orthogonal and normalized.

As far as I can tell, what you are doing is right.