Need help with my animation system.

Started by
1 comment, last by JackOfAllTrades 12 years, 7 months ago
I've been working very hard to get animations working in my game engine but I'm having a really hard time. My problem is actually pretty simple yet requires matrix math beyond my understanding. So far I've gotten it to rotate child bones based on the rotation of all bones before it. This works perfectly but I have a problem caused because the way key frames are stored in an FBX file and probably in all all animation systems. When I create a key rotation for a given bone all child bones of that bone have keys as well which are relative to all bones before it... I didn't think it worked like that when I started writing this function and now I'm having a hard time trying to think of how to use the keys properly. I know what needs to be done but I don't know how to do it... Here is the function:



void Ovgl::Actor::UpdateAnimation( int bone, Ovgl::Matrix44* matrix, float time )
{
// Initialize animation rotation matrix.
Ovgl::Matrix44 animRot;
animRot = Ovgl::MatrixIdentity();

// Get original pose of this bone and remove translation. Later this is used to convert animation to local space.
Ovgl::Matrix44 Rot;
Rot = mesh->bones[bone]->matrix;
Rot._41 = 0.0f;
Rot._42 = 0.0f;
Rot._43 = 0.0f;

// Search for a key for this bone.
for( unsigned int i = 0; i < mesh->keyframes[(unsigned int)time]->keys.size(); i++ )
{
if(mesh->keyframes[(unsigned int)time]->keys.index == bone)
{
// Create animation rotation matrix.
Ovgl::Vector3 Euler;
Euler.x = Ovgl::DegToRad(mesh->keyframes[(unsigned int)time]->keys.rotation.x);
Euler.y = Ovgl::DegToRad(mesh->keyframes[(unsigned int)time]->keys.rotation.y);
Euler.z = Ovgl::DegToRad(mesh->keyframes[(unsigned int)time]->keys.rotation.z);
animRot = Ovgl::MatrixRotationEuler(Euler.x, Euler.y, Euler.z);

// Convert animation to local space.
animRot = Ovgl::MatrixInverse( &Ovgl::Vector4(), &animRot) * Rot;
}
}

// Offset the center of rotation to the location of the bone.
animRot = Ovgl::MatrixInverse( &Ovgl::Vector4(), &mesh->bones[bone]->matrix) * animRot * mesh->bones[bone]->matrix;

// Get difference from original pose to the animated pose.
matrices[bone] = animRot * ((*matrix) * Ovgl::MatrixInverse( &Ovgl::Vector4(), &mesh->bones[bone]->matrix));

// Loop through all child bones and update their animations.
for( unsigned int i = 0; i < mesh->bones[bone]->childen.size(); i++)
{
Ovgl::Matrix44 accumulate;
accumulate = animRot * (*matrix) * Ovgl::MatrixInverse( &Ovgl::Vector4(), &mesh->bones[bone]->matrix ) * mesh->bones[mesh->bones[bone]->childen]->matrix;
Ovgl::Actor::UpdateAnimation( mesh->bones[bone]->childen, &accumulate, time );
}
}


Here is an image representation of my problem and how I need to solve it:

[attachment=5413:example.png]
Advertisement
I think little mnemonics would help you - it is really hard to dig through all those matrix inversions etc...

  • Bones form a hierarchy of transformations, where each bone has its own coordinate transformation relative to its parent. Let's call this transformation matrix B2P matrix (BoneToParent) - normally it has both translation and rotation parts
  • Animation keys usually define a new animated transformation relative to parent (normally only rotation part, but the idea is the same). Let's call it AB2P (AnimatedBoneToParent)
  • Now for each bone you'll want to find it's full transformation relative to animated object (mesh) itself. Let's call it B2M (BoneToMesh)
  • And also the same transformation while animated. Let's call it AB2M

Now you can do the following:

  1. While loading mesh, store B2P for each bone (I think this is your mesh->bones[bone]->matrix)
  2. At the same time, calculate B2M for each bone: [font="Courier New"]bone.B2M = parent.B2M * bone.B2P[/font]
  3. While updating bone animations, calculate AB2P from your animation keys
  4. Calculate AB2M for the bone: [font="Courier New"]bone.AB2M = parent.AB2M * bone.AB2P[/font]
You can do all these calcualtion with full matrices - no need to extract translation and rotation parts and apply these separately. The only exception is while extracting animation keys. If you have keys only for rotation, you have to compose AB2P from that rotation and the translation of the original bone matrix (B2P).

If you need the relative transformation of animated bone, compared to bone in rest pose, it is:

[font="Courier New"]AB2B = B2P(-1) * AB2P[/font]

Sometimes you need the relative transformation of animated skin compared to skin bind pose, for this bone (i.e. if doing weighted skinnining)

[font="Courier New"]AS2S = AB2M * B2M(-1)[/font]
Lauris Kaplinski

First technology demo of my game Shinya is out: http://lauris.kaplinski.com/shinya
Khayyam 3D - a freeware poser and scene builder application: http://khayyam.kaplinski.com/

I think little mnemonics would help you - it is really hard to dig through all those matrix inversions etc...

  • Bones form a hierarchy of transformations, where each bone has its own coordinate transformation relative to its parent. Let's call this transformation matrix B2P matrix (BoneToParent) - normally it has both translation and rotation parts
  • Animation keys usually define a new animated transformation relative to parent (normally only rotation part, but the idea is the same). Let's call it AB2P (AnimatedBoneToParent)
  • Now for each bone you'll want to find it's full transformation relative to animated object (mesh) itself. Let's call it B2M (BoneToMesh)
  • And also the same transformation while animated. Let's call it AB2M

Now you can do the following:

  1. While loading mesh, store B2P for each bone (I think this is your mesh->bones[bone]->matrix)
  2. At the same time, calculate B2M for each bone: [font="Courier New"]bone.B2M = parent.B2M * bone.B2P[/font]
  3. While updating bone animations, calculate AB2P from your animation keys
  4. Calculate AB2M for the bone: [font="Courier New"]bone.AB2M = parent.AB2M * bone.AB2P[/font]
You can do all these calcualtion with full matrices - no need to extract translation and rotation parts and apply these separately. The only exception is while extracting animation keys. If you have keys only for rotation, you have to compose AB2P from that rotation and the translation of the original bone matrix (B2P).

If you need the relative transformation of animated bone, compared to bone in rest pose, it is:

[font="Courier New"]AB2B = B2P(-1) * AB2P[/font]

Sometimes you need the relative transformation of animated skin compared to skin bind pose, for this bone (i.e. if doing weighted skinnining)

[font="Courier New"]AS2S = AB2M * B2M(-1)[/font]


Thank you for replying! Have you done this before and do you have any code I can look at? I think my function is completely unusable...

This topic is closed to new replies.

Advertisement