Archived

This topic is now archived and is closed to further replies.

mattbbangin

Skeletal Animation Tutorial

Recommended Posts

After weeks of trying to figure out why I couldn't get this (http://rsn.gamedev.net/tutorials/ms3danim.asp) to work, I finally got it. If I had only thought logically, I would've saved all of that time (the author could've thrown these little nuggets of info into the tutorial as well, it wouldn't hurt). So for anybody who is using this tutorial as a primer for skeletal animation, but wish to be left out of the loop when it comes to MS3D (like me), here's a list of things that would've saved me weeks of work had I known them: Please feel free to correct me if I've botched something. * All joints must have at least 4 keyframes (start and end; for both rotation and translation) (unless the joint is completely static), whether or not the keyframes represent a change in translation/rotation. * localTranslation and localRotation represent the offset a joint is from it's parent (or if the joint has no parent, then offset from {0,0,0}). * All rotations are in radians. * Rotations may or may not be stored in a less conventional way; YXZ (or Yaw, Pitch, Roll; or Heading, Attitude, Bank) [someone please confirm this] * The translations/rotations set in the keyframes represent the offsets from the respective joint's localTranslation/localRotations. * "Absolute" and "Relative" describe the values associated with the skeleton BEFORE any animation occurs. For instance, you CAN NOT use a joints absolute/relative matrices directly to find the absolute/relative position/rotation of a joint that has undergone hierarchical transformation. [don't quote me on this one] * The way the animation works, you CAN NOT simply just "leap into" the timeline at any time (ie, instead of using the Timer in AdvanceAnimation(), passing along a time value obtained from the user). You must first call Restart() and then AdvanceAnimation() each time the time value changes. Now I just have one last problem... I can find the absolute position of a joint that has undergone hierarchical transformation using this function:
static inline Vector3f DVBModel_FindJointPosition(DVBModel *model, int queryJoint)
{
    int jointIndex = queryJoint;
    Vector3f vec = ISOMath_MakeVector3f2(model->joints[jointIndex].localTranslation);
    
    do
    {
	jointIndex = model->joints[jointIndex].parentIndex;
	vec = ISOMath_Vector3fOpAdd(vec,ISOMath_MakeVector3f2(model->joints[jointIndex].localTranslation));
    } while(jointIndex!=-1);
    
    ISOMath_Vector3fInverseTransformByMatrix4x4(&vec.x, &model->joints[queryJoint].absolute);
    ISOMath_Vector3fTransformByMatrix4x4(&vec.x, &model->joints[queryJoint].final);
    
    return(vec);
}
       
I need the absolute position because I want to render a single point that represents each joint at their respective positions (with lines connecting child-parent pairs, representing the hierarchy). Rendering points at the absolute position of the joints is no problem. That brings me to my dilemma: I also want to render an axis model (consisting of 3 lines extending from the world origin along the X, Y, and Z axis) at the absolute position of each joint. So I could do this 2 different ways: Choice 1) Simply call glMultMatrix() along with the final matrix of the joint I'm rendering an axis model for. (Note: This is what I'm currently using, in hopes that someone can enlighten me to a more robust way). Choice 2) Call DVBModel_FindJointPosition() and somehow get 3 angles representing the joint's rotation from the joint's matrices. Choice 1 works like a charm, but all I can do is render. If I were using this for, let's say, a content-creation program (eg, modeler), I would prefer to use choice 2 (for versatile keyframing and whatnot). I figure I could just pull the rotation angles from the joint's final matrix using a function somewhat like this:
static inline Vector3f ISOMath_Matrix4x4GetRotationEuler(Matrix4x4 *matrix)
{
    Vector3f result;
    
    result.y = atan(matrix->values[1]/matrix->values[0]);
    result.x = atan(matrix->values[6]/matrix->values[10]);
    result.z = asin(-matrix->values[2]);
    
    return(result);
}
       
But it doesn't give. Any shred of insight? Thanks. [edited by - mattbbangin on April 23, 2004 8:46:05 AM]

Share this post


Link to post
Share on other sites