Calculating the correct roll from a bone transform matrix

| | August 10, 2015

Read this forum topic for more info: http://blenderartists.org/forum/showthread.php?260602-transform-matrix-to-bone-%28head-tail-roll%29-bug

I’m trying to get my Blender3d modeller importer to create correct bones from my file’s transform matrices.

The Blender Python API doesn’t have a way to do this (anymore!), so people had to dig the Blender C source to find out how Blender does it and port that. Here’s a Python port of the needed functions, not by me (I don’t know C):

def vec_roll_to_mat3(vec, roll):
    target = mathutils.Vector((0,1,0))
    nor = vec.normalized()
    axis = target.cross(nor)
    if axis.dot(axis) > 0.0000000001: # this seems to be the problem for some bones, no idea how to fix
        axis.normalize()
        theta = target.angle(nor)
        bMatrix = mathutils.Matrix.Rotation(theta, 3, axis)
    else:
        updown = 1 if target.dot(nor) > 0 else -1
        bMatrix = mathutils.Matrix.Scale(updown, 3)
    rMatrix = mathutils.Matrix.Rotation(roll, 3, nor)
    mat = rMatrix * bMatrix
    return mat

def mat3_to_vec_roll(mat):
    vec = mat.col[1]
    vecmat = vec_roll_to_mat3(mat.col[1], 0)
    vecmatinv = vecmat.inverted()
    rollmat = vecmatinv * mat
    roll = math.atan2(rollmat[0][2], rollmat[2][2])
    return vec, roll

How to use them:

pos = mymatrix.to_translation()
axis, roll = mat3_to_vec_roll(mymatrix.to_3x3())

bone = armature.edit_bones.new('name')
bone.head = pos
bone.tail = pos + axis
bone.roll = roll

Sadly, it seems even the Blender C code is buggy and doesn’t take into account cases when the bone is parallel to (0,1,0). So such bones can get assigned wrong (by 180 degrees) rolls and mess up animations.

Does anyone have better code for generating roll which takes into account such cases?

The old Blender 2.4 API generated correct ones. Its C code can be found here: http://svn.blender.org/svnroot/bf-blender/branches/blender-2.47/source/blender/blenkernel/intern/armature.c
I’m no C coder myself, again.

Leave a Reply