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 vecmat = vec_roll_to_mat3(mat.col, 0) vecmatinv = vecmat.inverted() rollmat = vecmatinv * mat roll = math.atan2(rollmat, rollmat) 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.