For testing/learning purposes I am trying to use quaternions in place of euler angles when doing the rotation/translation for the view camera. I managed to get everything to work with the exception that the camera is now rotating around the center-point axis rather than on it’s own axis. What do I need to do to achieve rotation on the camera’s own axis rather than rotating around the center axis?
Below is my code used for this test:
Any questions regarding to the code please let me know. I hope I’ve been descriptive enough for anyone to understand my situation.
void Draw(void)
{
vec4_t vec1;
vec4_t vec2;
vec4_t vec3;
double m[16];
....
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
M_SetQuaternion(&vec1, R_ViewAngleToEuler(cam_yaw), 0, 1, 0);
M_SetQuaternion(&vec2, R_ViewAngleToEuler(cam_pitch), 1, 0, 0);
M_MultiplyQuaternions(&vec3, &vec1, &vec2);
M_CalcRotationMatrix(&vec3, m);
M_CalcTranslationMatrix(m, cam_x, cam_y, cam_z);
// the stuff above is suppose to behave like this below:
// glRotatef(R_ViewAngleToEuler(cam_pitch), 1.0f, 0.0f, 0.0f);
// glRotatef(R_ViewAngleToEuler(cam_yaw), 0.0f, 1.0f, 0.0f);
// glTranslatef(cam_x, cam_y, cam_z);
glMultMatrixd(m);
....
glPopMatrix();
....
}
// here's the utilities used in case anyone wants to look
typedef struct
{
double x;
double y;
double z;
double w;
} vec4_t;
#define M_PI 3.1415926535897932384626433832795
#define M_RAD (M_PI / 180.0)
#define M_DEG (180.0 / M_PI)
float R_ViewAngleToEuler(float angle)
{
return angle * 0.0439453125f; // should probably not worry about this. This converts the game's angle value into euler degrees. Game's angle value ranges from -4096 to 4096
}
void M_CalcRotationMatrix(vec4_t* vec, double *m)
{
double xx = vec->x * vec->x;
double yx = vec->y * vec->x;
double zx = vec->z * vec->x;
double wx = vec->w * vec->x;
double yy = vec->y * vec->y;
double zy = vec->z * vec->y;
double wy = vec->w * vec->y;
double zz = vec->z * vec->z;
double wz = vec->w * vec->z;
double ww = vec->w * vec->w;
m[ 0] = ((ww + xx) - yy) - zz;
m[ 1] = (wz + wz) + (yx + yx);
m[ 2] = (zx + zx) - (wy + wy);
m[ 3] = 0.0;
m[ 4] = (yx + yx) - (wz + wz);
m[ 5] = (yy + (ww - xx)) - zz;
m[ 6] = (wx + wx) + (zy + zy);
m[ 7] = 0.0;
m[ 8] = (wy + wy + zx + zx);
m[ 9] = (zy + zy) - (wx + wx);
m[10] = ((ww - xx) - yy) + zz;
m[11] = 0.0;
m[12] = 0.0;
m[13] = 0.0;
m[14] = 0.0;
m[15] = 1.0;
}
void M_CalcTranslationMatrix(double *m, double x, double y, double z)
{
m[12] = x + m[12];
m[13] = y + m[13];
m[14] = z + m[14];
}
void M_MultiplyQuaternions(vec4_t *out, vec4_t *q1, vec4_t *q2)
{
out->x = q1->x * q2->w - q1->y * q2->z + q2->x * q1->w + q2->y * q1->z;
out->y = q1->x * q2->z + q1->y * q2->w - q2->x * q1->z + q1->w * q2->y;
out->z = q2->x * q1->y + q1->w * q2->z + q1->z * q2->w - q1->x * q2->y;
out->w = q1->w * q2->w - (q2->y * q1->y + q1->z * q2->z + q2->x * q1->x);
}
void M_Normalize4(vec4_t *out)
{
long double d;
d = sqrt(out->y * out->y + out->z * out->z + out->w * out->w + out->x * out->x);
if(d != 0.0)
{
out->x = out->x * 1.0 / d;
out->y = out->y * 1.0 / d;
out->z = out->z * 1.0 / d;
out->w = out->w * 1.0 / d;
}
}
void M_SetQuaternion(vec4_t* vec, double angle, double x, double y, double z)
{
double sin_a = sin((angle * M_RAD) * 0.5);
double cos_a = cos((angle * M_RAD) * 0.5);
vec->x = x * sin_a;
vec->y = y * sin_a;
vec->z = z * sin_a;
vec->w = cos_a;
M_Normalize4(vec);
}