# getting bone base and tip positions from a transform matrix?

I need this for a Blender3d script, but you don't really need to know Blender to answer this.

I need to get bone head and tip positions from a transform matrix read from a file. The position of base is the location part of the matrix, length of the bone (distance from base to tip) is the scale, position of the tip is calculated from the scale (distance from bone base) and rotation part of the matrix.

So how to calculate these?

``````bone.base([x,y,z]) # x,y,z - floats
bone.tip([x,y,z])
``````
-

You can find the base by multiplying the origin vector (0, 0, 0) by the transform matrix.

The tip question is slightly more in-depth: it really depends on what the canonical direction is that all the bones are defined from - in other words, where does the bone originally rotate from?

One way or another, to get the tip position you multiply a unit vector (for example, in Z this would be (0, 0, 1)) by the transformation matrix.

Bear in mind as well that your bones are probably hierarchical and the position will be relative to its parent joint - you will need to multiply one particular joint's matrix by its parent (and the parent joint by its parent, and so on) to get a global, world position.

-
No worries about hierarchy - isn't any. So what about the tip position? I think for the lenght you assumed bone's original rotation is facing the z-axis. Let's assume the same when calculating tip position. Now what is the actual formula? – ddos Jul 10 '12 at 5:33
I guess I don't need to get the size because by setting tip and base position that is set automatically. – ddos Jul 10 '12 at 5:44
That should be the answer. If the scale denotes the length, and rotation the direction, then multiplying a unit vector (Z if all bones originally faced Z, X if X, and so on) then the resulting position will be the tip's position. I'll modify the answer to correct that. – Matt Kemp Jul 10 '12 at 8:10
I just tried this with Blender 2.62 and it doesn't seem to work. I mean it works, the math is correct, but when inspecting a skeleton imported with my importer for Blender 2.4 and then Blender 2.6, you can see the bone roll (rotation relative to itself) is different. The same happens if you do `bone.tail = mathutils.Vector((0,1,0))` and then `bone.transform(mymatrix)`. – user17402 Jul 10 '12 at 16:11
I don't have Blender to hand, but how does it store the initial roll of the bone? If I understand you correctly the bone tip is in the correct place but the orientation is wrong. How does it store this orientation? If it's a normal vector, the solution is simple: multiply the normal by the matrix too (with the W component as zero, so (nX, nY, nZ, 0)). This will apply the rotation (and scale, so you'll probably have to re-normalize) without applying the translation. – Matt Kemp Jul 10 '12 at 20:13

If you want to preserve the original transform so that Blender's bones recreate the same transform, you will also need to calculate the bone roll.

Blender has a function to calculate the bone head, tail and roll from a transform matrix in C code. I haven't found a convenient way to access this functionality from the Python API, but fortunately the functions are short and can easily be translated into Python.

Below is a direct translation of the functions you need, for Blender 2.62 or later:

```def vec_roll_to_mat3(vec, roll):
target = Vector((0,1,0))
nor = vec.normalized()
axis = target.cross(nor)
if axis.dot(axis) > 0.000001:
axis.normalize()
theta = target.angle(nor)
bMatrix = Matrix.Rotation(theta, 3, axis)
else:
updown = 1 if target.dot(nor) > 0 else -1
bMatrix = Matrix.Scale(updown, 3)
rMatrix = 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

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

Yeah OK. I'm also having trouble settings poseMatrices when bones are parented. But that's a separate question I'll post tomorrow. Thanks for your help. BTW, I fixed those few bones by increasing the floating point precision here: `if axis.dot(axis) > 0.0000000001` – user17402 Jul 10 '12 at 21:21