5

In Blender 2.6 API, PoseBone is used for animating a bone. PoseBone.matrix is one way to do that. API says PoseBone.matrix is in "object space".

http://www.blender.org/documentation/blender_python_api_2_63_5/bpy.types.PoseBone.html#bpy.types.PoseBone.matrix

PoseBone.matrix is nothing I've seen at all. I still can't get my animation importer working. What's the deal with PoseBone.matrix? In Blender 2.4 API there were two matrices: one in local space, one in armature space.

But the new PoseBone.matrix is neither! It's not a local matrix:

enter image description here

Position isn't local, it's global.

But rotation enter image description here

<Euler (x=1.5708, y=-0.7854, z=-0.0000), order='XYZ'> 

is.

So what is this "object space" that the API says PoseBone.matrix is in?

I'm trying to assign my armature-space matrices to a hierarchial armature and I can't get them right.

I tried decomposing the matrices I have, undoing parent rotations then recomposing the matrix again before setting it as "PoseBone.matrix". It just doesn't work.

oldmatrix = myMatrix
loc, rot, scale = oldmatrix.decompose()

#rot = rot * pose.bones[bonename].parent.rotation_quaternion.conjugated()
for i in pose.bones[bonename].parent_recursive:
   rot = rot * i.conjugated()

newmatrix = rot.to_matrix().to_4x4()

newmatrix[0][3] = loc.x
newmatrix[1][3] = loc.y
newmatrix[2][3] = loc.z

pose.bones[bonename].matrix = newmatrix 

2 Answers2

2

EDIT: I found the solution that transforms these Object Space transforms to Bone Local Space.

To cut the long story short - here's a code snippet that accomplishes that task:

    poseBone = C.object.pose.bones[2]  # <----- set your bone here

    # poseBone.matrix is in object space - we need to convert it to local space 
    if poseBone.parent is not None:
        parentRefPoseMtx = poseBone.parent.bone.matrix_local
        boneRefPoseMtx = poseBone.bone.matrix_local
        parentPoseMtx = poseBone.parent.matrix
        bonePoseMtx = poseBone.matrix

        boneLocMtx = ( parentRefPoseMtx.inverted() * boneRefPoseMtx ).inverted() * ( parentPoseMtx.inverted() * bonePoseMtx )

    else:
        boneRefPoseMtx = poseBone.bone.matrix_local
        bonePoseMtx = poseBone.matrix

        boneLocMtx = boneRefPoseMtx.inverted() * bonePoseMtx

    loc, rot, scale = boneLocMtx.decompose()

MY OLD QUESTION:

Have you found the solution yet? I'm dealing with exactly the same problem.

Object space matrix should be the bone local space matrix expressed with respect to the parent's object space matrix, so:

boneOS = parentOS * boneLS

But as you noticed - it doesn't give the correct solution. The bone is still offset. One thing that came to my mind was that it's offset by the rest pose transform, so I tried rolling it back, but that didn't work either, but perhaps the equations I used were wrong.

Here's how I tried calculating the local space transform of a pose bone ( let's assume bone 1 is the bone of my interest, and bone 0 is its parent, and that 0 doesn't have a parent ):

boneOS = C.object.pose.bones[2].matrix
parentBoneOS = C.object.pose.bones[2].parent.matrix

boneRP = C.object.pose.bones[2].bone.matrix_local  # rest pose matrix in bone local space
parentBoneRP = C.object.pose.bones[1].bone.matrix_local  # parent bone's rest pose matrix in bone local space

boneLS = ( parentBoneRP * boneRP ).inverted() * parentOS.inverted() * boneOS
Piotr Trochim
  • 693
  • 5
  • 15
  • Have you actually tried that on a script? Heres an example script and blend http://stackoverflow.com/questions/11722391/apply-non-hierarchial-transforms-to-hierarchial-skeleton?rq=1 Doesn't work. –  Jun 29 '13 at 07:35
  • Can you remove the bits of your answer that aren't actually an answer? You should not be asking questions in answer threads. – tacaswell Sep 21 '13 at 16:19
0

The matrix is in object-space and it should behave like you expect from your code. What's happening is that the bones' matrices aren't being updated immediately after changing the matrix. So far I've found a hack-solution of updating the entire scene after every bone with

bpy.context.scene.update()
nickhar
  • 19,981
  • 12
  • 60
  • 73
Miko
  • 33
  • 4