PDA

View Full Version : Interpolating With Matrices/Quaternions



twoski
10-23-2014, 07:29 AM
So i am making a simple program in opengl that allows the user to create a list of keyframes then animates a skeleton through those keyframes using 4 different types of interpolation.

I have implemented the keyframe system. It is essentially a vector of skeletons, and a skeleton is just a collection of joint structs which contain information (local transform, global transform, etc) for each joint in the skeleton.

Each joint in the skeleton hierarchy has a vector3 position, a local transform matrix and a global transform matrix.

Here is the draw code:



for (unsigned i=0; i<joints.size(); i++)
{
glPushMatrix();
if (joints[i].isPicked)
glColor3f(1.0, 0.0, 0.0);
else if (joints[i].isHovered)
glColor3f(0.1, 1.0, 0.1);
else
glColor3f(0.3, 0.3, 0.9);

glMultMatrixf(joints[i].global_t);

glTranslated(joints[i].position.x, joints[i].position.y, joints[i].position.z);
glutSolidSphere(0.01, 15, 15);
glTranslated(-joints[i].position.x, -joints[i].position.y, -joints[i].position.z);

if (joints[i].parentID !=-1)//draw bones for all joints
{
glColor3f(0.7, 0.3, 0.3);
glBegin(GL_LINES);
glVertex3d(joints[i].position.x, joints[i].position.y, joints[i].position.z);
glVertex3d(joints[joints[i].parentID].position.x,
joints[joints[i].parentID].position.y,
joints[joints[i].parentID].position.z);
glEnd();
}
glPopMatrix();
}

For each joint we multiply by the global transform, then translate.

So given 2 different skeletons, each with distinct joints, I need to interpolate between them given an arbitrary float between 0 and 1 inclusive.



void Interpolate(float fract)
{
Keyframe cur = keyframes[keyframe]; // note that Keyframe is a struct which contains "joints" which is a vector of joint structs
Keyframe next = keyframes[keyframe + 1];
Keyframe result = cur;
result.number = cur.number;

switch(interpMode)
{
case 1:
for (unsigned i=0; i<cur.joints.size(); i++)
{
for (int j = 0; j < 15; j++)
{
result.joints[i].local_t[j] = cur.joints[i].local_t[j] * (1-fract) + next.joints[i].local_t[j] * fract;
}
}
break;
case 2:
//euler
break;
case 3:
//quaternion
break;
case 4:
//slerp quaternion
break;
}

myDefMesh.mySkeleton.joints = result.joints;
}

This code doesn't do anything, i need to update the global transform after altering the local transform i think. Can anyone provide insight?

GClements
10-23-2014, 08:07 AM
i need to update the global transform after altering the local transform i think.
Correct.

But there's no point trying to interpolate matrices, the results will be garbage. Euler angles or axis-and-angle won't be much better. This is why everyone uses quaternions.

twoski
10-23-2014, 10:36 AM
Agreed, this program is meant to show what each method looks like, even if they are wrong. It's more of a demonstration as to why quaternions are ideal for this sort of thing.

Dark Photon
10-24-2014, 05:46 AM
This is why everyone uses quaternions.
Right, or dual quaternions, which handle the translation component too.