local matrix from global matrix? (bone)

Started by
5 comments, last by dewey__ 11 years, 8 months ago
I've heard of this answer: multiply the object's (bone's) matrix by the inverse of the parent's matrix, but it doesn't quite work.

I use Blender, but the question might not be API specific.

I have some matrices I need to assign to PoseBones (bones used for animating). The resulting pose looks fine when there is no bone hierarchy (parenting) and messed up when there is.

WWXa9.png

I've uploaded an archive with sample blend of the rigged models, test animation importer and a test animation file here: http://www.2shared.c...mple_files.html
Import the animation by selecting an Armature and running the importer on "sba" file. Do this for both Armatures.

This is how I assign the poses in the real (complex) importer:


matrix_bases = ... # matrix from file
animation_matrix = matrix_basis * pose.bones['mybone'].matrix.copy()
pose.bones[bonename].matrix = animation_matrix


If I go to edit mode, select all bones and press Alt+P to undo parenting, the Pose looks fine again.
The API documentation says the PoseBone.matrix is in "object space", but it seems clear to me from these tests that they are relative to parent bones.

Final 4x4 matrix after constraints and drivers are applied (object space)[/quote]

I tried doing something like this:


matrix_basis = ... # matrix from file
animation_matrix = matrix_basis * (pose.bones['mybone'].matrix.copy() * pose.bones[bonename].bone.parent.matrix_local.copy().inverted())
pose.bones[bonename].matrix = animation_matrix


But it looks worse. Experimented with order of operations, no luck with all.
For the record, in the old 2.4 API this worked like a charm:


matrix_basis = ... # matrix from file
animation_matrix = armature.bones['mybone'].matrix['ARMATURESPACE'].copy() * matrix_basis
pose.bones[bonename].poseMatrix = animation_matrix
pose.update()


Link to Blender API ref:
http://www.blender.o...types.BlendData
http://www.blender.o....types.PoseBone

I've tried the blender forums (several times) with no answer.
Advertisement
I have taken a look at your import script and it appears to be fine. I ran it Blender 2.63.

My question is within the test.sba; are the matrices only rotations or do they have combined rotations with parent?
It looks like the import reads the matrices 'as is' and apply it to the bone key frame.

If this is the case with the test.sba:
Within Blender, the armature without parent bones appear to work correctly (and it is) because the key frame matrix have a combined parent/child rotation.
Now for the armature that has parent bones, it appears incorrect because the bone rotations are being applied twice. (Bone rotation + parent rotation + parent rotation in blender)

I think that is what is going on here since I haven't picked apart the test.sba

Edit:

I've heard of this answer: multiply the object's (bone's) matrix by the inverse of the parent's matrix, but it doesn't quite work.[/quote]

This must be done with the bones within the test.sba in order to only get the rotation of the bone in question. Then with that rotation, apply it to the key frame matrix. The armature with parent/child bone structure should work then. I suppose there should be a conditional check somewhere in the script for parent/child bone armatures to determine if the inverse parent's matrix method is even needed.
The matrices in the files are armature space, no relative stuff. The matrices store location, rotation and scaling (usually just 1,1,1).
However I want to be able to apply it to an Armature which has bone hierarchy (parenting).

It's actually an old game format. So sadly I can't just change the way the animation format works.
But I don't think that's necessary is it? We just need to convert matrix spaces.

I tried this before, but you can see that it does something different:


if pose.bones[bonename].parent: # if has parent bone
parentmat = pose.bones[bonename].bone.parent.matrix_local.copy().inverted()

pose.bones[bonename].matrix = frames[frame][bonenumber] * parentmat
else:
pose.bones[bonename].matrix = frames[frame][bonenumber]

just replace the line "pose.bones[bonename].matrix = frames[frame][bonenumber]" with this.
It's actually an old game format.[/quote]

What game?

I have a question about the script; what is the purpose for sorting the bones by name?

for bonename in sorted(pose.bones.keys()):

In the blend file the root bone is "2"; middle bone is "0", and last bone is "1".
Using pose.bone.keys() by itself returns bones 2,0,1

After sorting it's 0,1,2 making it middle, last, root
In the script, the sba matrices are read into the frames in the order of 0,1,2 and repeat for each frame.
Are the matrices in the sbp file in the order of middle, last, root?
How do you get a sba file? Is this something you exported from Blender?
If you're wondering if the problem comes from assigning the matrices in wrong order, then don't worry, that's not it. After all the Blender 2.4 version of my script works perfectly, as I've said already.

And don't forget this is an example format and example importer in the archive I uploaded.

And of course you can check if its in correct order by loading the anim file on the left Armature.
meh
:(

I just noticed that assigning an animation matrix to a PoseBone changes the matrix. What?

<Matrix 4x4 (-0.0147, 0.0409, -0.9991, 0.3136)
( 0.0093, 0.9991, 0.0407, -0.0768)
( 0.9998, -0.0087, -0.0150, 9.2912)
( 0.0000, 0.0000, 0.0000, 1.0000)>
<Matrix 4x4 (-0.0000, -0.0000, -1.0000, -0.0000)
(-0.0000, 1.0000, -0.0000, -0.1500)
( 1.0000, 0.0000, -0.0000, 9.3372)
( 0.0000, 0.0000, 0.0000, 1.0000)>
from file/in PoseBone

This topic is closed to new replies.

Advertisement