I'm having some trouble animating a 3D model. I am just trying to do a simple rotation on x, y and z through 360 degrees. So my goal is to be able to pitch, roll and yaw the model through any rotation angle. The code below uses a combination of matrices and quaternions to accomplish this. But despite that the resulting animation appears to have gimbal lock. It starts to spin correctly but then suddenly slows down and appears to go backwards for a moment before carrying on.
You'll see that I am trying to use pitch, roll and yaw angles to do this. Maybe it is that I need to completely get away from using these kinds of angles and come at this from another perspective. Anyway, I thought I would post my code here and see if people can point out to me why it's not working and what I really ought to be doing.
Here is the sudo code in brief;
The model data that I load comes out upside-down initially so first thing I do is flip 180 degrees on z.
I then do the translation to push the model away from the viewport a little.
I then do three stages of rotation, I extract the look, up and right vectors from the matrix create quaternions based on those vectors and my stored values for pitch roll and yaw. I then convert the quaternion back into a matrix and multiply the current matrix by it. But I do it sequentially, I apply the multiplication for each quaternion-matrix before getting the vector values for the next one from the resulting matrix. I also have to invert the quaternions to make the pitch, roll and yaw angles move in the direct direction since I originally did a flip on z.
So despite all this I still have gimbal lock, any advice or help is welcome - even if it's extended use of the "don't bat"
Code: Select all
static GLfloat scale = 1.0f;
static GLfloat pitch = 0.0f;
static GLfloat yaw = 0.0f;
static GLfloat roll = 0.0f;
static void drawView(STATE_T *state, EGL_NSH_MODEL *model)
{
glLoadIdentity();
pitch = (pitch == 360) ? 0 : pitch + 1;
yaw = (yaw == 360) ? 0 : yaw + 1;
roll = (roll == 360) ? 0 : roll + 1;
Matrix3D identityMatrix;
Matrix3DSetIdentity(identityMatrix);
Matrix3D flipMatrix;
Matrix3DSetRotationByDegrees(flipMatrix, 180.0f, 0.0f, 0.0f, 1.0f); //Flip model on z
glMultMatrixf(flipMatrix);
Matrix3D transScaleMatrix;
Matrix3DSetTranslationScaling(transScaleMatrix, scale, scale, scale, 0.0f, 0.0f, -25.0);
glMultMatrixf(transScaleMatrix);
Matrix3D transformedMatrix;
glGetFloatv(GL_MODELVIEW_MATRIX, transformedMatrix);
//-------------
Vector3D rollVector;
rollVector.x = transformedMatrix[2];
rollVector.y = transformedMatrix[6];
rollVector.z = transformedMatrix[10];
Quaternion3D rollQuat;
rollQuat = Quaternion3DMakeWithAxisAndAngle(rollVector, DegreesToRadians(roll));
Quaternion3DInvert(&rollQuat);
Matrix3D rollMatrix;
Matrix3DSetUsingQuaternion3D(rollMatrix, rollQuat);
glMultMatrixf(rollMatrix);
Matrix3D rollResultMatrix;
glGetFloatv(GL_MODELVIEW_MATRIX, rollResultMatrix);
//-------------
Vector3D yawVector;
yawVector.x = rollResultMatrix[1];
yawVector.y = rollResultMatrix[5];
yawVector.z = rollResultMatrix[9];
Quaternion3D yawQuat;
yawQuat = Quaternion3DMakeWithAxisAndAngle(yawVector, DegreesToRadians(yaw));
Quaternion3DInvert(&yawQuat);
Matrix3D yawMatrix;
Matrix3DSetUsingQuaternion3D(yawMatrix, yawQuat);
glMultMatrixf(yawMatrix);
Matrix3D rollYawResultMatrix;
glGetFloatv(GL_MODELVIEW_MATRIX, rollYawResultMatrix);
//-------------
Vector3D pitchVector;
pitchVector.x = rollYawResultMatrix[0];
pitchVector.y = rollYawResultMatrix[4];
pitchVector.z = rollYawResultMatrix[8];
Quaternion3D pitchQuat;
pitchQuat = Quaternion3DMakeWithAxisAndAngle(pitchVector, DegreesToRadians(pitch));
Quaternion3DInvert(&pitchQuat);
Matrix3D pitchMatrix;
Matrix3DSetUsingQuaternion3D(pitchMatrix, pitchQuat);
glMultMatrixf(pitchMatrix);
Matrix3D rollYawPitchResultMatrix;
glGetFloatv(GL_MODELVIEW_MATRIX, rollYawPitchResultMatrix);
//-------------
glClearColor(0.0, 0.0, 0.0, 1.0);
glClearDepthf(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, model->vertices);
glColorPointer(4, GL_FLOAT, 0, model->colors);
glDrawElements(GL_TRIANGLES, model->polysCount, GL_UNSIGNED_SHORT, model->polys);
glLineWidth(2.0f);
glDrawElements(GL_LINES, model->linesCount, GL_UNSIGNED_SHORT, model->lines);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
eglSwapBuffers(state->display, state->surface);
}
