Proper concatenation of matrix transforms for skeletal animation?

This topic is 4251 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I have been working on a skeletal animation system for the past few weeks, initially using quaternions for both bone orientation and bone transforms. However, while this worked fine for cases where only one bone is allowed to rotate, as illustrated below, the transforms would be incorrect for cases where child bones are allowed to rotate as well. After much frustration, I tried to implement a matrix version of the transforms, since there seems to be much more literature on that subject, but unfortunately, I got similar results. Initial pose Pose with only upper legs allowed to rotate And here are the problem cases: Pose with upper and lower legs allowed to rotate Pose with upper, lower legs and feet allowed to rotate Since the problems only arise when there are hierarchical rotations, I'm guessing that there is something wrong with how I am concatenating the transforms. As you can see in the fourth image, the feet are totally disconnected from the rest of the body, as well as the lower legs. The way I am doing the transforms is by first calculating the default origin of every bone (in model space), and then storing in each bone a matrix of the form: T(-default model space bone origin) * R(rotation from keyframe data) * T(default model space bone origin) Then, right before the transforms for each vertex are calculated, each bone's matrix is multiplied by its parent's matrix. I know that if I apply the transforms separately on each vertex (that is, apply (-T)*R*T for each bone, in succession, from the most extreme child down to the root) it will probably work correctly. However, the textbooks seem to say that you can mix everything down to one transform. Given that I am working on a high-poly game, I would like to be able to avoid all those additional operations, if they are indeed unnecessary. So what am I doing wrong?

Share on other sites
You're missing the displacements from the parent bones. Storing the rotations as quaternions is fine, but I think that for computing the actual transforms matrices are easier since they contain both displacements and rotations (and scaling, but it's unusual to use that in skeletal animation). Right now I think your bone origins are being calculated relative to the position of the model, but really they need to be calculated relative to the position of the parent bones.

Share on other sites
Quote:
 Original post by VorpyYou're missing the displacements from the parent bones. Storing the rotations as quaternions is fine, but I think that for computing the actual transforms matrices are easier since they contain both displacements and rotations (and scaling, but it's unusual to use that in skeletal animation). Right now I think your bone origins are being calculated relative to the position of the model, but really they need to be calculated relative to the position of the parent bones.

Currently, my total matrix transform for a three-bone system would look like this:

(T(-global root bone origin) * R(root bone rotation) * T(global root bone origin)) * (T(-global bone #2 origin) * R(bone #2 rotation) * T(global bone #2 origin)) * (T(-global bone #3 origin) * R(bone #3 rotation) * T(global bone #3 origin))

So, then the total matrix transform should be something like the following?

T(-global root bone origin) * R(root bone rotation) * T(root bone to bone #2) * R(bone #2 rotation) * T(bone #2 to bone #3) * R(bone #3 rotation) * T(bone #3 global origin)

Share on other sites
Something like that, I think, yes. Except for that global bone #3 origin at the end, since bone 3 should only be positioned relative to bones 1 and 2. I think the origins of the bones should be at the joints.

Share on other sites
Still not working. :(

Here's a thought, though. Do the child bone displacements need to be prerotated before being multiplied into the total matrix transform?

Rotation about a single point is of the form T(-point) * R(root) * T(point), right? After rotating a point about the root bone, couldn't you perform the same rotation on the origin of bone #2 and then do a separate transformation of the form T(-rotated bone #2 origin)* R(root * bone #2 rotation) * T(rotated bone #2 origin)?

As you'll note, at present, the unrotated displacements are what I am using. Perhaps that is the problem?

It would make sense because the transform for bone N is dependent upon the transforms of all bones before N.

Share on other sites
Fixed it. Here's what I learned:

1) T(-global bone origin) * R(bone) * T(global bone origin) works perfectly (since -global of one bone plus global of the next will equal the displacement between them), but you have to prerotate the bone origins before you concatenate the matrices. A matrix with translation (x,y,z) concatenated to a string of matrices MEANS a translation of (x,y,z) NO MATTER WHAT.

2) When converting quaternion transforms to matrices, ALWAYS check your W components. Not doing this can cause your translations to have no effect, or a much greater effect than intended.

Thanks anyway for your help. You got me thinking, and thinking solves problems. :)

1. 1
2. 2
Rutin
15
3. 3
4. 4
5. 5

• 13
• 26
• 10
• 11
• 9
• Forum Statistics

• Total Topics
633725
• Total Posts
3013563
×