I have an animated rig and I am trying to calculate the transformation matrix of a particular pose bone. Here are the relevant values at a frame:

bone.location -> Vector((0.25549933314323425, 0.3193724751472473, 1.4211256504058838))

bone.rotation_quaternion -> Quaternion((0.9943733811378479, -0.09154314547777176, -0.019470931962132454, -0.04962115362286568))

`bone.scale -> Vector((1, 1, 1))

And the actual transformation matrix at the same from I get with bone.matrix is:

Matrix(((0.9943171739578247, 0.10224877297878265, -0.02963779866695404, 0.25549933314323425),
        (-0.08072073012590408, 0.5426188111305237, -0.8360914587974548, -1.1943329572677612),
        (-0.06940729171037674, 0.8337326049804688, 0.5477888584136963, 0.4846082329750061),
        (0.0, 0.0, 0.0, 1.0)))

Now I need to get the above matrix with the given rotation and location values, but am unable to get it.

I tried the following

matrix = (Matrix.Rotation(bone.rotation_quaternion.angle, 4, bone.rotation_quaternion.axis) @ Matrix.Translation(bone.location))


matrix = (Matrix.Translation(bone.location) @ bone.rotation_quaternion.to_matrix().to_4x4())

Both the above approaches give different results.

So given bone location and translation how do I get the matrix that matches with bone.matrix. I need this because I need the matrix at a different frame. And I can't get it directly, I can only get location and Quaternion rotation using fcurve.evaluate.


1 Answer 1


Calculating PoseBone.matrix from Fcurves

The right-hand side of the first expression you tried is in reverse order. Also it's PoseBone.matrix_basis, not PoseBone.matrix.

matrix_basis = Matrix.Translation(bone.location) @ Matrix.Rotation(bone.rotation_quaternion.angle, 4, bone.rotation_quaternion.axis)

Recursive call is required to obtain matrix from matrix_basis. And here is an example of doing this without view_layer.update() or scene.frame_set(). The script below is a modified version of that sample.

import bpy
from mathutils import Matrix, Vector, Quaternion

def get_matrix_basis_from_fcurve(pbone, fcurves, frame):

    vecs = [Vector(), Vector([1,1,1,1])]
    props = ('location', 'scale')
    for j in range(len(props)):
        data_path = pbone.path_from_id(props[j])
        for i in range(3):
            fc = fcurves.find(data_path, index=i)
            if fc is None:
            vecs[j][i] = fc.evaluate(frame)
    trans = Matrix.Translation(vecs[0])
    scale = Matrix.Diagonal(vecs[1])

    data_path = pbone.path_from_id('rotation_quaternion')
    quat = Quaternion()
    temp_quat = Quaternion()
    for i in range(4):
        fc = fcurves.find(data_path, index=i)
        if fc is None:
        temp_quat[i] = fc.evaluate(frame)
        quat = temp_quat
    rot = quat.to_matrix().to_4x4()
    return trans @ rot @ scale

def get_pose_matrices(obj, matrix_map, frame):
    "Assign pose space matrices of all bones at once, ignoring constraints."

    fcurves = obj.animation_data.action.fcurves

    def rec(pbone):

        matrix_basis = get_matrix_basis_from_fcurve(pbone, fcurves, frame)

        # Compute the updated pose matrix from local and new parent matrix
        if pbone.parent:
            matrix_map[pbone.name] = pbone.bone.convert_local_to_pose(
            matrix_map[pbone.name] = pbone.bone.convert_local_to_pose(

        # Recursively process children, passing the new matrix through
        for child in pbone.children:

    # Scan all bone trees from their roots
    for pbone in obj.pose.bones:
        if not pbone.parent:

obj = bpy.context.object
matrix_map = {}
frame = 12
get_pose_matrices(obj, matrix_map, frame)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .