# Quaternions with a 6DOF camera?

Hello. I am working on a Wing Commander style game in C, but have run into a problem: gimbal lock. I think my best option (?) is to use Quaternions.

I was looking for a tutorial, but all I could find was a few advanced maths ones or nehe’s tutorial : written in C++, and he doesn’t include the class, so it will be impossible to port to C.

Can anyone please help me use Quaternions? Or suggest a better option? Or point me to a tutorial?

Thanks

A good article, but a bit old. Perhaps someone has a better one?:

http://www.gamasutra.com/view/feature/3278/rotating_objects_using_quaternions.php

BTW I’m making a 3d space game too, in Java. I did learn quaternions from that article. See my firm for the link to my game’s blog.

Thanks, I don’t have the time to check it now but I hope it works. Also, I like your space game, the look around the cockpit is cool. Good luck with it

Glad to know you like my game

Yeah thanks but I don’t really understand. Can I just check:

Here are my two functions:

``````eulerToQuat(float qroll, float qpitch, float qyaw, QUAT * quat)
{
float cr, cp, cy, sr, sp, sy, cpcy, spsy;
// calculate trig identities
cr = cos(qroll/2);
cp = cos(qpitch/2);
cy = cos(qyaw/2);
sr = sin(qroll/2);
sp = sin(qpitch/2);
sy = sin(qyaw/2);
cpcy = cp * cy;
spsy = sp * sy;
quat->w = cr * cpcy + sr * spsy;
quat->x = sr * cpcy - cr * spsy;
quat->y = cr * sp * cy + sr * cp * sy;
quat->z = cr * cp * sy - sr * sp * cy;
}

quatToMatrix(QUAT * quat)
{

float x2 = quat->x * quat->x;
float y2 = quat->y * quat->y;
float z2 = quat->z * quat->z;
float xy = quat->x * quat->y;
float xz = quat->x * quat->z;
float yz = quat->y * quat->z;
float wx = quat->w * quat->x;
float wy = quat->w * quat->y;
float wz = quat->w * quat->z;

// This calculation would be a lot more complicated for non-unit length quaternions
// Note: The constructor of Matrix4 expects the Matrix in column-major format like expected by
//   OpenGL
return Matrix4( 1.0f - 2.0f * (y2 + z2), 2.0f * (xy - wz), 2.0f * (xz + wy), 0.0f,
2.0f * (xy + wz), 1.0f - 2.0f * (x2 + z2), 2.0f * (yz - wx), 0.0f,
2.0f * (xz - wy), 2.0f * (yz + wx), 1.0f - 2.0f * (x2 + y2), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f)

}
``````

And what I should do:

1. Make quaternion from PITCH, ROLL, and YAW
2. Multiply quaternion to the current one
3. glMultMatrixf(newquaternion);

???

Should I translate before I rotate? Or after?

Note that you also need the function for quaternion multiplication, from the same article.

1 and 2 are ok, but in 3 you obtain the matrix from the current quaternion and then use that matrix in the glMultMatrixf call.

After.

Well, thanks for answering, but I have two more (rather stupid) questions:

After.

So I just need to do glTranslate3f(0.0f,.0.0f,AIRSPEED) after I have rotated?

1. What is the storage for matrixes? float matrix[4][4]? How do I return arrays from my matrix functions?

1- No, you want to translate in the direction of movement. It is the z vector of the matrix

2- Yes. In C, to return an array you declare the function

``````float * functionName() { ...
``````

All OpenGL fixed-function stores matrices as vectors (column major ordering)

(float matrix[16] not float matrix[4][4])

Column-major matrix order. So an array of columns.

float matrix[4][4]?

You could use that, but you have to use a trick. OpenGL matrices are column-major order and OpenGL follows the operator-on-the-left convention (Mv1=v2). C/C++ arrays are row-major. You can use row-major and get the same exact values in exactly the same matrix cells as column-major if you reverse the multiplication order – that is, use operator-on-the-right convention (v1M=v2) with row-major C/C++.

How do I return arrays from my matrix functions?

With C/C++, arrays are weird. You can’t return them by value, and it sounds like that’s what you want. Easiest is to put float m[4][4] inside a class, and then it works. This is good for a number of other reasons too – you can assign methods to the matrix storage.

For a tiny bit more efficiency, you can pass the target matrix along the the source matrices as arguments of your matrix functions. E.g. multMatrix( Mat4 &result, const Mat4 &a, const Mat4 &b );. This may eliminate a copy to your matrix result.

OK my euler to quat function doesn’t work but I will try to rewrite them so I can return quaternions.

Hmmm. So I now have my functions working (new ones I stole borrowed developed :whistle: ) but strange things are happening. It’s hard to describe exactly but It seems that every time I change the matrix (move the mouse or rotate the ship) the world shears and rotates and scales in all different manners. I think I have reversed the row-column stuff. Here’s my code:

``````
//glRotatef(pitch, 1.0f, 0.0f, 0.0f);

xaxis.x = 1.0f;
yaxis.y = 1.0f;
zaxis.z = 1.0f;

q1 = quatMult( eulerToQuat(xaxis, pitch), eulerToQuat(yaxis, heading));
q1 = quatMult( eulerToQuat(zaxis, roll) , q1);

//quatMultiply(q1, q2, q2);
shipMatrix = quatToMatrix(q1);

glMultMatrixf(  shipMatrix.m );

glTranslatef(-xp,0.0f,0.0f);

glTranslatef(0.0f,-yp,0.0f);

glTranslatef(0.0f,0.0f,-zp);

drawSpace();

``````

And the respective functions:

``````quaternion eulerToQuat(vec3D axis, float angle)
{
quaternion quat;
float sinAngle;

angle *= 0.5f;
normVec3D(&axis);
sinAngle = sin(angle);
quat.x = (axis.x * sinAngle);
quat.y = (axis.y * sinAngle);
quat.z = (axis.z * sinAngle);
quat.w = cos(angle);

return quat;
}

quaternion quatMult(quaternion  quat2, quaternion quat3)
{
vec3D vector1, vector2, cross;
quaternion quat1;
float angle;

vector1.x = quat1.x;
vector1.y = quat1.y;
vector1.z = quat1.z;
vector2.x = quat2.x;
vector2.y = quat2.y;
vector2.z = quat2.z;
angle = (quat1.w * quat2.w) - dotprodVec3D(vector1, vector2);

cross = crossprodVec3D(vector1, vector2);
vector1.x *= quat2.w;
vector1.y *= quat2.w;
vector1.z *= quat2.w;
vector2.x *= quat1.w;
vector2.y *= quat1.w;
vector2.z *= quat1.w;

quat1.x = vector1.x + vector2.x + cross.x;
quat1.y = vector1.y + vector2.y + cross.y;
quat1.z = vector1.z + vector2.z + cross.z;
quat1.w = angle;

return quat1;
}

``````

matrix quatToMatrix(quaternion quat) {
matrix qmatrix;

``````qmatrix.m[0]  = (1.0f - (2.0f * ((quat.y * quat.y) + (quat.z * quat.z))));
qmatrix.m[1]  =         (2.0f * ((quat.x * quat.y) + (quat.z * quat.w)));
qmatrix.m[2]  =         (2.0f * ((quat.x * quat.z) - (quat.y * quat.w)));
qmatrix.m[3]  = 0.0f;
qmatrix.m[4]  =         (2.0f * ((quat.x * quat.y) - (quat.z * quat.w)));
qmatrix.m[5]  = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.z * quat.z))));
qmatrix.m[6]  =         (2.0f * ((quat.y * quat.z) + (quat.x * quat.w)));
qmatrix.m[7]  = 0.0f;
qmatrix.m[8]  =         (2.0f * ((quat.x * quat.z) + (quat.y * quat.w)));
qmatrix.m[9]  =         (2.0f * ((quat.y * quat.z) - (quat.x * quat.w)));
qmatrix.m[10] = (1.0f - (2.0f * ((quat.x * quat.x) + (quat.y * quat.y))));
qmatrix.m[11] = 0.0f;
qmatrix.m[12] = 0.0f;
qmatrix.m[13] = 0.0f;
qmatrix.m[14] = 0.0f;
qmatrix.m[15] = 1.0f;

return qmatrix;
``````

}

``````

``````

I have a feeling I am almost there, but while I’m here, I might as well ask if you think my translation functions are OK:

``````	xp += cos(DEG_TO_RAD * (heading - 90.0f ) )     *   airspeed * dt;
zp += sin(DEG_TO_RAD * (heading - 90.0f) ) *  airspeed * dt;
yp +=  sin(DEG_TO_RAD   * -pitch )  * airspeed  *  dt;
``````

Just in case anyone reads this, I got it working!!! Yipee!

Thankyou Yomboprime and everyone who helped me!

Yes I added the constant DEG_TO_RAD to multiply pitch, heading and roll before I send them to the quaternion functions.
Could you help with translating along the z axis of a quaternion/matrix?