Sign in to follow this  

Skeletal Animation - Non-uniform Scale

Recommended Posts

hi, I am currently implementing scaling into my animation system. I have gotten uniform scaling working, but non-uniform scaling is proving to be quite tricky. When I apply the same trivial transformations with non-uniform scales, the character I am animating appears wavy and looks like it shears or something. I am trying to understand mathematically why non-uniform scaling poses such a problem. I have done some searching, but it hasn't been easy to find a good source of information on this topic. Does anyone know of a good source of information on this? I have found some sources on general skeletal animation systems, but I only see mention to non-uniform scaling and that it is generally a pain ;) And if it makes a diffrence, I am exporting the animation data out of Maya. Any bits of information are appreciated! Cheers

Share this post

Link to post
Share on other sites
Are you performing the "animation" in bone-space, and then composing the transforms from parent to child in order to achieve your actual skinning matrices? If yes, you may need to be careful about inheriting scale. Whereas rotation and translation are generally inherited, you generally don't want to inherit scale. This would mean you'd need to first evaluate the whole skeleton to achieve the model-space bone matrices, then make another pass to apply the each bone's animated scaling. If you did want to inherit scale, then could easily be introducing "shearing" or "skewing" (i.e., take a child bone, scale it, rotate it, then scale the parent bone; if the two are on different axes, you'll get a shear).

The other alternative I suppose is that you're performing the animation in model-space, without performing any kind of hierarchical matrix composition. If this is the case, I don't think you'd have the same issues... though maybe there's still some other issue that I'm not thinking of immediately.

Share this post

Link to post
Share on other sites

Non-uniform is always tricky :)
It always complicates things. It is anoying I can say from my own experiences ;)

The solution for 3D Studio Max and Maya are a bit different. Since you mentioned Maya I will tell you about that one.

When you construct a local space matrix (relative to parent) for your node, I assume you do this from a position, rotation and scale vector. What you have to simulate is the Maya transform pipeline. Like I said Max has a different way though. The transform pipeline of Max and Maya are very complex, not really made for realtime. However we can simplify it for realtime engines.

You'd have to do this:

1.) Build a scale matrix with your node scale value
2.) Rotate this matrix by the rotation
3.) Scale this matrix by the inverse scale of the parent
4.) Set the translation of the matrix

It took me a while to get it right as well :)
Step 3 was the fix to get it working correctly in my case.

Example code:

// calculate the inverse parent scale
Vector3 invParentScale(1.0f, 1.0f, 1.0f);
invParentScale /= localTransforms[parentIndex].mScale;

localMatrices[nodeNumber].SetScaleMatrix( localTransform.mScale );
localMatrices[nodeNumber].MultMatrix3x3( Matrix::RotationMatrix(localTransform.mRotation) );
localMatrices[nodeNumber].Scale3x3( invParentScale );
localMatrices[nodeNumber].SetTranslation( localTransform.mPosition );

Hope this can prevent some people spending lots of time trying to get it to work with Maya! :)

For 3D Studio Max I use another way, which uses scale rotation, which rotates the object into its scale space before applying the scale, and then rotates it back again.

Also I do optimizations that take optimized paths for nodes without scale.

Share this post

Link to post
Share on other sites
Thanks for the input.

Yes, the animation keyframes are in local space and the keyframes are stored as seperate translation, rotation and scale components. After all the keyframe interpolation has been done I create each joint's local transform, then make a pass over the hierarchy to create each's composed matrix.

What's interesting about Maya is that there seems to be several different ways to get the transform information of the joints. When I traverse the hierarchy in maya and get their local transforms, I've been extracting the information from the joint's local transforms. Child nodes of parents that have scale seem to already have an inverse scale applied to them to counteract the parent's scale. Though, their scale is relative to their joint orientation, which I may have not been taking into account.

Original post by Buckshag
For 3D Studio Max I use another way, which uses scale rotation, which rotates the object into its scale space before applying the scale, and then rotates it back again.

That's interesting. Wouldn't you want to have each tool export out in the same format so that you can use the same algorithms for posing? I've heard others mention doing the scale rotation transformations, why wouldn't I have to do that for maya's data?

The steps you showed seem to be fairly simple, I hope I am extracting the data from maya correctly- if that's all I have to do then I'd be very happy :)

Anyway, I have a bit more to go on, so thanks for the help so far guys. ;)

Share this post

Link to post
Share on other sites
In general, avoid scaling for games characters like the plague. The problem Maya has specifically is that there are a number of transform types, and they compute matrices differently.

MFnTransform >> uses scale + rotate pivots, and rotation orients. You also need to take into account the inverse parent scale, and the translational offset to fix pivots correctly.

MFnIkJoint >> no pivots, only has rotation axes and joint orients to worry about. Also have to apply the inverse parent scale.

MPxTransform >> The user can compute a matrix any way they want.

The best way to extract the animation data from Maya is to use the MDagPaths to get a world space TM (inclusiveMatrix()), multiply by the parent nodes inverse world TM, then decompose the matrix manually. This subverts all the problems with Maya's transform system.

It's not just non-uniform scaling, it's all scaling that poses a problem. The problem is however easily fixed with the inverse parent scale. In general though, it's easier to just make sure you don't use scale at all (or, bake the scale out when you decompose the matrices). Scaling at the very end of a transform hierarchy won't however cause any problems (other than causing non uniform vertex normals).

Share this post

Link to post
Share on other sites
One problem with non-uniform scaling even if you get the transforms correct:

Imagine hand clapping animation where each hand supposed to touch each other at some point. If you apply non-uniform scale, the arms might get longer/shorter/fatter/whatever, torso size changed, etc. that may cause the hands no longer touch each other correctly.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this