As in the following code, matrix_local does not change before and after executing obj.matrix_local = Matrix.Rotation(math.pi/6, 4, 'X').

# Blender 3.6.0

import bpy
import math
from mathutils import Matrix



obj = bpy.context.active_object
mat_prev = obj.matrix_local.copy()
obj.matrix_local = Matrix.Rotation(math.pi/6, 4, 'X')

print("After - Before =" )
print(obj.matrix_local - mat_prev)
After - Before =
<Matrix 4x4 (0.0000, 0.0000, 0.0000, 0.0000)
            (0.0000, 0.0000, 0.0000, 0.0000)
            (0.0000, 0.0000, 0.0000, 0.0000)
            (0.0000, 0.0000, 0.0000, 0.0000)>

On the other hand, using matrix_world or matrix_basis instead of matrix_local changed them.

After - Before =
<Matrix 4x4 (0.0000,  0.0000,  0.0000, 0.0000)
            (0.0000, -0.1340, -0.5000, 0.0000)
            (0.0000,  0.5000, -0.1340, 0.0000)
            (0.0000,  0.0000,  0.0000, 0.0000)>

It's weird that the behavior changes depending on the type of matrix. I asked the reason because it might cause trouble in the future.


1 Answer 1


I'll quote blender dev response on the same issue.

The matrix_local property doesn't really exist in the object.

When you assign the obj.matrix_local the matrix gets decomposed and assigned to loc/rot/scale components of the object. (The parent inverse matrix is "cancelled" from the matrix before decomposition). Can follow rna_Object_matrix_local_set -> BKE_object_apply_mat4 When you read the property it is read from object's evaluated matrix (Object::obmat). The parent object's inverse matrix is "cancelled" from it as well (to get local matrix, as the property name suggests). The obmat is evaluated by the dependency graph, so that it will have constraints properly taken into account. Can follow that via rna_Object_matrix_local_get -> BKE_object_matrix_local_get

I can illustrate it with code from blender tracker. If you run it in default blender scene you can see from system console that matrix_local is appearing to be unchanged. BUT if you update view_layer after you assign new matrix to matrix_local (uncomment line in the code below to do that), you'll see that matrix_local is now also updated.

import bpy
from mathutils import Matrix

obj = bpy.data.objects["Cube"]
print("Before: ", obj.matrix_local)
m = Matrix.Translation((2.0, 3.0, 4.0))
obj.matrix_local = m

# uncomment the line below for matrix to update
# bpy.context.view_layer.update()
print("After: ", obj.matrix_local)

PS Agree that it's a bit weird and probably should be documented in docs.


You must log in to answer this question.

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