can't set the bone matrix in python

i’m trying to set the matrix of a bone, the bone is child of an asymetric scaled bone,

my code :

print(mat)
b.matrix = mat.copy()
print(b.matrix)

output:

<Matrix 4x4 ( 1.0000, 0.0000, -0.0000, 0.0000)
(-0.0000, 0.0000, -1.0000, 0.7021)
( 0.0000, 1.0000, 0.0000, 1.1347)
( 0.0000, 0.0000, 0.0000, 1.0000)>
<Matrix 4x4 ( 1.0000, 0.0000, -0.0000, 0.0000)
(-0.0000, 0.4629, -1.0359, 0.7021)
(-0.0000, 1.0364, -0.0531, 1.1347)
( 0.0000, 0.0000, 0.0000, 1.0000)>

it’s diferent , is there any way to fix it??

PoseBone.matrix is read-only (relative world), use PoseBone.matrix_basis to set matrix (relative rest pose and parent). PoseBone.bone.matrix_local is the rest pose matrix (relative armature).

To spell it out a bit more explicitly. The following code


import bpy
from mathutils import Matrix
pb = bpy.context.active_pose_bone
print("Before")
print(pb.matrix)
tmat = Matrix()
print("Target")
print(tmat)
rmat = pb.bone.matrix_local
if pb.parent:
    rpmat = pb.parent.bone.matrix_local
    pmat = pb.parent.matrix
    pb.matrix_basis = rmat.inverted() * rpmat * pmat.inverted() * tmat
else:
    pb.matrix_basis = rmat.inverted() * tmat
print("After")
print(pb.matrix)

produces the following output


Before
&lt;Matrix 4x4 (-0.4802,  0.8565,  0.1894, 0.1953)
            (-0.0032,  0.2142, -0.9768, 0.0267)
            (-0.8772, -0.4697, -0.1001, 1.5846)
            ( 0.0000,  0.0000,  0.0000, 1.0000)&gt;
Target
&lt;Matrix 4x4 (1.0000, 0.0000, 0.0000, 0.0000)
            (0.0000, 1.0000, 0.0000, 0.0000)
            (0.0000, 0.0000, 1.0000, 0.0000)
            (0.0000, 0.0000, 0.0000, 1.0000)&gt;
After
&lt;Matrix 4x4 ( 1.0000, -0.0000, -0.0000, 0.0000)
            (-0.0000,  1.0000, -0.0000, 0.0000)
            ( 0.0000,  0.0000,  1.0000, 0.0000)
            ( 0.0000,  0.0000,  0.0000, 1.0000)&gt;

Thanks ThomasL, that is super helpful!

One question: if the target matrix is provided in world space, how would i go about it?

import bpy
from mathutils import Matrix
pb = bpy.context.active_pose_bone
tmat = bpy.context.object.matrix_world.inverted() * Matrix() # world space =&gt; object space?
rmat = pb.bone.matrix_local
if pb.parent:
    rpmat = pb.parent.bone.matrix_local
    pmat = pb.parent.matrix
    pb.matrix_basis = rmat.inverted() * rpmat * pmat.inverted() * tmat
else:
    pb.matrix_basis = rmat.inverted() * tmat

thanks for your responses, i solved it for my account, the domain of matrices that bones can take is limited because they are decomposed in translation, rotation, and scaling. I was trying (wrongly) to set to the bone a asymmetric scale matrix (for approximated softbody simulation) its the reason the matrices were different (they are decomposed and then they are composed again) , I fixed the problem by using a ‘stretch to’ constraint