Blender 2.5 Python - Getting bone quaternions

Hi there,

I’m trying to export armature data from Blender 2.5. I know I can access bones like this:

bpy.data.armatures[i].bones[j]

and that each bone has the following useful properties:

  • length
  • head
  • head_local
  • tail
  • tail_local
  • matrix
  • matrix_local

However, I wish to represent the bone’s bind-pose rotation as a quaternion in my file format. I know I could convert matrix_local into a quaternion, but I assume there’s a better way. Could anyone offer some insight?

Thanks,
Ross.

As far as I know, your idea is a good one!

Converting the matrices to quaternions works, but the process is long-winded and it’s very likely that there’s a better way. If anyone knows or finds out, give me a shout.

Here’s the function I used to convert them, in case anyone else wants to do the same thing:

#Convert a 3*3 rotation matrix into a quaternion
def MatrixToQuaternion( mat ):

	quat = [0, 0, 0, 0]
	trace = mat[0][0] + mat[1][1] + mat[2][2] + 1
    
	if trace > 0.00001:
		s = math.sqrt( trace ) * 2
		quat[0] = s / 4.0
		quat[1] = ( mat[2][1] - mat[1][2] ) / s
		quat[2] = ( mat[0][2] - mat[2][0] ) / s
		quat[3] = ( mat[1][0] - mat[0][1] ) / s
        
	elif mat[0][0] > mat[1][1] and mat[0][0] > mat[2][2]:
            
		s = math.sqrt( 1 + mat[0][0] - mat[1][1] + mat[2][2] ) * 2
		quat[0] = ( mat[2][1] - mat[1][2] ) / s
		quat[1] = s / 4.0
		quat[2] = ( mat[1][0] + mat[0][1] ) / s
		quat[3] = ( mat[0][2] - mat[2][0] ) / s

	elif mat[1][1] > mat[2][2]:            

		s = math.sqrt( 1 + mat[1][1] - mat[0][0] - mat[2][2] ) * 2
		quat[0] = ( mat[0][2] - mat[2][0] ) / s
		quat[1] = ( mat[1][0] + mat[0][1] ) / s
		quat[2] = s / 4.0
		quat[3] = ( mat[2][1] + mat[1][2] ) / s

	else:     
		s = math.sqrt( 1 + mat[2][2] - mat[0][0] + mat[1][1] ) * 2
		quat[0] = ( mat[1][0] - mat[0][1] ) / s
		quat[1] = ( mat[0][2] + mat[2][0] ) / s
		quat[2] = ( mat[2][1] + mat[1][2] ) / s
		quat[3] = s / 4.0

	return quat

what about obj.matrix_local.to_quat() ?

Not totally equivalent in Blender 2.55 , try it with an rotated Cube



import bpy
from mathutils import *
import math
#Convert a 3*3 rotation matrix into a quaternion
def MatrixToQuaternion( mat ):

        quat = [0, 0, 0, 0]
        trace = mat[0][0] + mat[1][1] + mat[2][2] + 1
    
        if trace > 0.00001:
                s = math.sqrt( trace ) * 2
                quat[0] = s / 4.0
                quat[1] = ( mat[2][1] - mat[1][2] ) / s
                quat[2] = ( mat[0][2] - mat[2][0] ) / s
                quat[3] = ( mat[1][0] - mat[0][1] ) / s
        
        elif mat[0][0] > mat[1][1] and mat[0][0] > mat[2][2]:
            
                s = math.sqrt( 1 + mat[0][0] - mat[1][1] + mat[2][2] ) * 2
                quat[0] = ( mat[2][1] - mat[1][2] ) / s
                quat[1] = s / 4.0
                quat[2] = ( mat[1][0] + mat[0][1] ) / s
                quat[3] = ( mat[0][2] - mat[2][0] ) / s

        elif mat[1][1] > mat[2][2]:            

                s = math.sqrt( 1 + mat[1][1] - mat[0][0] - mat[2][2] ) * 2
                quat[0] = ( mat[0][2] - mat[2][0] ) / s
                quat[1] = ( mat[1][0] + mat[0][1] ) / s
                quat[2] = s / 4.0
                quat[3] = ( mat[2][1] + mat[1][2] ) / s

        else:     
                s = math.sqrt( 1 + mat[2][2] - mat[0][0] + mat[1][1] ) * 2
                quat[0] = ( mat[1][0] - mat[0][1] ) / s
                quat[1] = ( mat[0][2] + mat[2][0] ) / s
                quat[2] = ( mat[2][1] + mat[1][2] ) / s
                quat[3] = s / 4.0

        return quat

import time

mat = bpy.context.active_object.matrix_local
print(mat)
q1=(Quaternion(MatrixToQuaternion( mat )))
q2=(mat.to_quat())
print(q1,q2)
print(q1-q2)

e.g:
Quaternion((0.982884407043457, 0.1508471667766571, -0.06662704050540924, 0.08212287724018097)) Quaternion((0.9828845262527466, -0.1508471816778183, 0.06662704795598984, -0.08212288469076157))
Quaternion((-1.1920928955078125e-07, 0.3016943335533142, -0.13325408101081848, 0.16424575448036194))

1 minus in the last three components?

and checking the time


import time

mat = bpy.context.active_object.matrix_local
print(mat)
q1=(Quaternion(MatrixToQuaternion( mat )))
q2=(mat.to_quat())
print(q1,q2)
print(q1-q2)
oldtime = time.time()
for i in range(100000):
    Quaternion(MatrixToQuaternion( mat ))
    
res=(time.time()-oldtime)    
print(res)

oldtime = time.time()
for i in range(100000):
    mat.to_quat()
    
res=(time.time()-oldtime)    
print(res)

gives:

1.44799995422
0.137000083923

meaning the builtin conversion is 10 times faster!!!