# Bone matrix assignment behaviour change in Blender 2.80

I am trying to port an armature importer add-on from Blender 2.79 to Blender 2.8x.

After the bone is being created the bone matrix is set.

But the assignment of the bone matrix has a different behaviour in Blender 2.82a compared to the older Blender 2.79b.

I created a small script that works for both Blender versions to reproduce this behaviour:

import bpy
from mathutils import *

def new_armature(name: str) -> bpy.types.Object:
armature = bpy.data.armatures.new(name)
obj = bpy.data.objects.new(name, armature)

if bpy.app.version[1] >= 80:
bpy.context.view_layer.objects.active = obj
else:
bpy.context.scene.objects.active = obj

return obj

obj = new_armature('human')
armature = obj.data

bpy.ops.object.mode_set(mode='EDIT')

new_bone = armature.edit_bones.new('Bone.000')

new_bone.tail = Vector([1, 0, 0])

bone_matrix = Matrix(([0,0,1,0],[0,-1,0,-6],[-1,0,0,6],[0,0,0,1]))
print("bone_matrix:\n", bone_matrix)

new_bone.matrix = bone_matrix
print("new_bone.matrix:\n", new_bone.matrix)



Running that script in Blender 2.79b and Blender 2.82a gives me the following outputs:

user@desktop:~/workspace/blender$blender2.79b --python test2.py --background Read prefs: /home/user/.config/blender/2.79/config/userpref.blend found bundled python: /opt/blender/2.79b/2.79/python bone_matrix: <Matrix 4x4 ( 0.0000, 0.0000, 1.0000, 0.0000) ( 0.0000, -1.0000, 0.0000, -6.0000) (-1.0000, 0.0000, 0.0000, 6.0000) ( 0.0000, 0.0000, 0.0000, 1.0000)> new_bone.matrix: <Matrix 4x4 (0.0000, 0.0000, 1.0000, 0.0000) (0.0000, -1.0000, 0.0000, -6.0000) (1.0000, 0.0000, -0.0000, 6.0000) (0.0000, 0.0000, 0.0000, 1.0000)> Blender quit user@desktop:~/workspace/blender$ blender2.82a --python test2.py --background
Blender 2.82 (sub 7) (hash 375c7dc4caf4 built 2020-03-12 05:30:40)
found bundled python: /opt/blender/2.82a/2.82/python
bone_matrix:
<Matrix 4x4 ( 0.0000,  0.0000, 1.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
(-1.0000,  0.0000, 0.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>
new_bone.matrix:
<Matrix 4x4 (-1.0000,  0.0000, 0.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
( 0.0000,  0.0000, 1.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>

Blender quit


As you can see, the new_bone.matrix matrix differes between these versions.

Updating the scene also does not change anything.

Can you give me a hint how to get the Blender 2.79b behaviour in Blender 2.82a?

My platform is Linux with Kubuntu 19.10 x64.

There is bone_matrix in left-handed system. It makes no sense to consider the differences between versions when the wrong parameters are inputted into Blender.

bone_matrix in left-handed system:
<Matrix 4x4 ( 0.0000,  0.0000, 1.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
(-1.0000,  0.0000, 0.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>

bone_matrix in right-handed system:
<Matrix 4x4 ( 0.0000,  0.0000, 1.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
( 1.0000,  0.0000, 0.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>

• Thanks for your answer! It's possible that the matrix is wrong. The origin matrix targeted directX, so left-handed system. Maybe there is something wrong with the matrix conversion from directX coordinate system to blender's coordinate system. Do you have a solution how to convert a matrix from directx coordinate system to blender coordinate system? – phil535 Jun 19 '20 at 18:40

The resultant rotation of both matrices is equivalent.

If we look at the quaternion rotation of each matrix can get the angular difference

Using 2.90 alpha and tacking following onto script

print("bone_matrix:\n", bone_matrix)
print(bone_matrix.to_euler())
new_bone.matrix = bone_matrix
print("new_bone.matrix:\n", new_bone.matrix)

print(new_bone.matrix.to_euler())

q = bone_matrix.to_quaternion() # M1
q2 = new_bone.matrix.to_quaternion() # M2
print(q, q2)

from math import degrees

print("Rotate M1", degrees(angle), "about axis", axis, "to match M2")


Output

bone_matrix:
<Matrix 4x4 ( 0.0000,  0.0000, 1.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
(-1.0000,  0.0000, 0.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>
<Euler (x=-3.1416, y=1.5708, z=0.0000), order='XYZ'>
new_bone.matrix:
<Matrix 4x4 (-1.0000,  0.0000, 0.0000,  0.0000)
( 0.0000, -1.0000, 0.0000, -6.0000)
( 0.0000,  0.0000, 1.0000,  6.0000)
( 0.0000,  0.0000, 0.0000,  1.0000)>
<Euler (x=0.0000, y=-0.0000, z=3.1416), order='XYZ'>
<Quaternion (w=0.0000, x=0.0000, y=0.0000, z=1.0000)>
<Quaternion (w=0.0000, x=0.0000, y=0.0000, z=1.0000)>

Rotate M1 0.0 about axis <Vector (0.0000, 1.0000, 0.0000)> to match M2


The quaternions are same.

Looking at the Euler angles will notice that the end results (in degrees)

Euler((360, 180, 0))


is equivalent to

Euler((0, 0, 360))


This is often seen as gimbal lock in Eulers were two eqivalent rotation matrices flip flop.

Would favour the more well formed nature of M2 with values on the principle diagonal.

Suggestion, using quaternion rotation for bones makes sure they have a singular value per rotation.