# Rotations using quaternions - still experiencing gimbal lock?

Hi all,

I’m working on a 3D skeletal animation app,
I’m rather confused as to the best way to perfrom bone rotations,
at first I just had the rotation angles stored in the bone struct and I calculated a matrix from that, this doesn’t work correctly as depending in what order rotations are made it doesn’t always turn out the same…

After much searching I came to the conclusion that my app was suffering from “gimbal lock” and that the correct way to solve the problem is to use quaternions to calculate the rotations…

I have tried quaternions with no improvment … unless I’m just using them incorrectly.

Basically I have a bone struct something like:

``````struct bone {
float rang[3];
float rquat[4];
float matrix[16];
/* Some other stuff here (parent, children, position etc..) */

}
``````

Now when a user rotates a bone I simply adjust the appropriate angle - rang[0] being X and so on…
Then I calculate the rotation quaternions the usual way, and multiply them by each other, this becomes the quaternion rquat in the bone struct,
I also multiply it by the parent bone’s rquat.
This is then converted to a matrix which represents the bones final rotation…

After all this it makes no difference to my original system which used only matrices?

I have also worked out another system,
I modifiy the bone struct a bit:

``````struct bone {
/*float rang[3];*/
float rquat[4];
float quat[4];
float matrix[16];
/* Some other stuff here (parent, children, position etc..) */

}
``````

I now have two quaternions in a bone, when the bone is initialised I set the quaternion rquat to the identity, and every time the user rotates the bone I multiply rquat by a rotation quaternion,
on rendering this gets multiplied by the parent bone’s quat and becomes quat which is converted into a matrix…

Ok now this system works perfectly - no gimbal lock, rotations always occur exactly as they ought.
But the problem with this system is I don’t know what angles are represented by this quaternion?
And therfore how to present them to the user?

It must be possible as most modelling/animation apps are able to present the user with a simple set of angles to modify.

Any ideas or clues?
Thanks!

Well after some more searching, I’ve actually come across the formula to convert a quaternion into euler angles, I’ve created a function like this:

``````#define RADDEG (M_PI/180.0)

void quat_to_euler(float quat[4], float *x, float *y, float *z)
{
float sqx = quat[0] * quat[0];
float sqy = quat[1] * quat[1];
float sqz = quat[2] * quat[2];
float sqw = quat[3] * quat[3];

float unit = sqx + sqy + sqz + sqw;
float test = quat[0]*quat[1] + quat[2]*quat[3];

if (test > 0.499*unit) {
*x = 0;
*y = (2 * atan2(quat[0], quat[3]) / RADDEG);
} else if (test < -0.499*unit) {
*x = 0;
*y = (-2 * atan2(quat[0], quat[3])) / RADDEG;
} else {
*x = atan2(2*quat[0]*quat[3] - 2*quat[1]*quat[2], -sqx + sqy - sqz + sqw) / RADDEG;
*y = atan2(2*quat[1]*quat[3] - 2*quat[0]*quat[2], sqx - sqy - sqz + sqw) / RADDEG;
}

if (x < 0) x += 360.0;
if (y < 0) y += 360.0;
if (z < 0) z += 360.0;
}
``````

This seems to work OK, except that the reported angles are a bit odd,

If I rotate any one angle (alone) it reports the angle from 0 up to 360 degrees correctly.
But say I rotate x by 45, and then I rotate y by -90 degrees it reports: x = 0, y = 270, z = 315.

Which I suppose is actually the same thing…
So it doesn’t really matter… but it might confuse the users a bit…