i’m trying to get some euler angle to quaternion conversion code working and having some difficulty.
the goal is to take a set of euler angles (rotX, rotY, rotZ) and convert to a quaternion (q). then to take (q) and convert to (angle, vector) form for rotation in opengl.
in real code, of course, the conversion from euler to quaternion will happen a single time, so only the conversion from quaternion to angle, vector form needs to be quick.
quickness, however, is not currently the issue. the problem is that my code (see big chunk below) does not produce the quaternion equivelant of euler angles. it produces some other seemingly arbitrary rotation. now: if only one euler angle is used (rotation about one and only one axis), then it seems to be correct.
am i missing something totally obvious? is there something horribly wrong with my code? have i been staring at it too long?
any help much appreciated!
#define DEGREE_TO_RADIAN ((3.1415926535897932384626433832795 * 0.5) / 180.0)
#define RADIAN_TO_DEGREE (180.0 / (3.1415926535897932384626433832795 * 0.5))// define a simplistic quaternion type
typedef struct t_Quaternion {
float x, y, z, w;
} Quaternion;// declare five quaternion: one for each Euler angle, one temporary, and the final result.
Quaternion qx, qy, qz, qt, q;// use these angle for this test
float rotX = 90.0f;
float rotY = 90.0f;
float rotZ = 90.0f;
// calculate each Euler-angle-equivelant quaternion:
// X
qx.w = cos(rotX * 0.5 * DEGREE_TO_RADIAN);
qx.x = sin(rotX * 0.5 * DEGREE_TO_RADIAN);
qx.y = 0;
qx.z = 0;qy.w = cos(rotY * 0.5 * DEGREE_TO_RADIAN);
qy.x = 0;
qy.y = sin(rotY * 0.5 * DEGREE_TO_RADIAN);
qy.z = 0;qz.w = cos(rotZ * 0.5 * DEGREE_TO_RADIAN);
qz.x = 0;
qz.y = 0;
qz.z = sin(rotZ * 0.5 * DEGREE_TO_RADIAN);
// find the product of qx * qy * qz
// temporary quaternion is the product of qx and qy.
qt.w = qx.w * qy.w - qx.x * qy.x - qx.y * qy.y - qx.z * qy.z;
qt.x = qx.w * qy.x + qx.x * qy.w + qx.y * qy.z - qx.z * qy.y;
qt.y = qx.w * qy.y + qx.y * qy.w + qx.z * qy.x - qx.x * qy.z;
qt.z = qx.w * qy.z + qx.z * qy.w + qx.x * qy.y - qx.y * qy.x;// final quaternion is the product of qt and qz
q.w = qt.w * qz.w - qt.x * qz.x - qt.y * qz.y - qt.z * qz.z;
q.x = qt.w * qz.x + qt.x * qz.w + qt.y * qz.z - qt.z * qz.y;
q.y = qt.w * qz.y + qt.y * qz.w + qt.z * qz.x - qt.x * qz.z;
q.z = qt.w * qz.z + qt.z * qz.w + qt.x * qz.y - qt.y * qz.x;
// now, we have the final quaternion: convert it into
// angle and vector form
float cos_angle = q.w;
float angle = acos( cos_angle ) * 2 * RADIAN_TO_DEGREE;
float sin_angle = sqrt( 1.0 - cos_angle * cos_angle );float sa = sin_angle;
if ( fabs( sin_angle ) < 0.0005 )
sa = 1;float vx = q.x / sa;
float vy = q.y / sa;
float vz = q.z / sa;// use the angle-vector form to perform rotation.
glRotatef(angle, vx, vy, vz);/**
- Mysteriously, the above does not seem to be equivelant to:
- glRotatef(rotX, 1.0, 0.0, 0.0);
- glRotatef(rotY, 0.0, 1.0, 0.0);
- glRotatef(rotZ, 0.0, 0.0, 1.0);
*/