5

The Setup:

I have a simple setup with two cube objects with a parent child relationship like so:

Objects in Blender

The Red cube is a child object of the green cube.

The Red cube has the following transforms:

Transform of red cube in Blender

The green cube has the following transforms:

Transform of red cube in Blender

The Problem

The thing I am confused about is, when I try to decompose the local_matrix of the red cube and compose it back to its original transform matrix. I get different results. Below is a script I used to decompose and compose the local matrix. Any clues why they are different? And what is the correct way to re-compose the local matrix given the translation, rotation and scale matrices.

Script and Result

import bpy
import mathutils
import math

myObject = bpy.data.objects['Cube.002']

print("\n location mat") loc = myObject.matrix_local.to_translation() print(loc) mat_loc = mathutils.Matrix.Translation(loc) print(mat_loc)

print("\n rotation mat") rot = myObject.matrix_local.to_quaternion() print(rot) mat_rot = rot.to_matrix().to_4x4() print(mat_rot)

print("\n scale mat") scl = myObject.matrix_local.to_scale() print(scl) mat_scl = mathutils.Matrix.Identity(4) mat_scl_x = mathutils.Matrix.Scale(scl.x, 4, (1,0,0)) mat_scl_y = mathutils.Matrix.Scale(scl.y, 4, (0,1,0)) mat_scl_z = mathutils.Matrix.Scale(scl.z, 4, (0,0,1)) mat_scl = mat_scl_x @ mat_scl_y @ mat_scl_z print(mat_scl)

print("\n myLocalMat mat") myLocalMat = mat_loc @ mat_rot @ mat_scl print(myLocalMat)

print("\n local mat") print(myObject.matrix_local)

 location mat
<Vector (0.0000, 0.0000, 3.0000)>
<Matrix 4x4 (1.0000, 0.0000, 0.0000, 0.0000)
            (0.0000, 1.0000, 0.0000, 0.0000)
            (0.0000, 0.0000, 1.0000, 3.0000)
            (0.0000, 0.0000, 0.0000, 1.0000)>

 rotation mat
<Quaternion (w=0.9280, x=0.0000, y=0.0000, z=0.3726)>
<Matrix 4x4 (0.7224, -0.6915, 0.0000, 0.0000)
            (0.6915,  0.7224, 0.0000, 0.0000)
            (0.0000,  0.0000, 1.0000, 0.0000)
            (0.0000,  0.0000, 0.0000, 1.0000)>

 scale mat
<Vector (1.5811, 1.5811, 1.0000)>
<Matrix 4x4 (1.5811, 0.0000, 0.0000, 0.0000)
            (0.0000, 1.5811, 0.0000, 0.0000)
            (0.0000, 0.0000, 1.0000, 0.0000)
            (0.0000, 0.0000, 0.0000, 1.0000)>

 myLocalMat mat
<Matrix 4x4 (1.1422, -1.0934, 0.0000, 0.0000)
            (1.0934,  1.1422, 0.0000, 0.0000)
            (0.0000,  0.0000, 1.0000, 3.0000)
            (0.0000,  0.0000, 0.0000, 1.0000)>

 local mat
<Matrix 4x4 (1.4142, -1.4142, 0.0000, 0.0000)
            (0.7071,  0.7071, 0.0000, 0.0000)
            (0.0000,  0.0000, 1.0000, 3.0000)
            (0.0000,  0.0000, 0.0000, 1.0000)>

Best Regards. QC

  • See https://blender.stackexchange.com/questions/169416/does-a-child-object-inherit-the-matrix-from-the-parent It's the basis matrix you see in the UI. If you have parented via UI have set the parent inverse. Can decompose with Matrix.decompose() – batFINGER May 26 '21 at 12:46
  • @batFINGER Thanks for the reply. I was not comparing the transform in the UI to the transforms in the script result. I was only doing this to a transform matrix: Decompose --> recompose. And yet I get different matrices with the same parameters in the script – QuantumCoderQC May 26 '21 at 13:15
  • Thanks again, I tried to visualize by setting the matrix_local to the matrix that I composed. The changes were: The object's rotation along the z axis changed from 45 to 42.8; the scale changed from (1, 1, 1) to (1.23, 1.23, 1). These changes were observed in the viewport.. – QuantumCoderQC May 26 '21 at 13:57

1 Answers1

6

Using the 3x3 matrix rotation part.

Does a child object inherit the matrix from the parent?

Can decompose a matrix via Matrix.decompose()

loc, rot, scale = M.decompose()

the rotation is given as a quaternion. There is no guarantee that that the same rotation matrix will be returned when converting that quaternion back to a matrix. https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Rotation_matrix_%E2%86%94_quaternion

Test script, with both "standard" quaternion decompose and using the 3x3 rotation matrix part.

import bpy
from mathutils import Matrix

ob = bpy.context.object

basis (or local) matrix

Mb = ob.matrix_local

print("Input") print(Mb)

t, q, s = Mb.decompose()

T = Matrix.Translation(t)

R = q.to_matrix().to_4x4()

S = Matrix.Diagonal(s.to_4d())

M = T @ R @ S print("Quaternion decompose") print(M)

print((M.to_3x3() - Mb.to_3x3()).determinant())

R = Mb.to_3x3().normalized().to_4x4()

T = Matrix.Translation( Mb.to_translation() )

S = Matrix.Diagonal( Mb.to_scale().to_4d() )

M = T @ R @ S

print("3 x 3 decompose") print(M)

print((M.to_3x3() - Mb.to_3x3()).determinant())

Sample output.

Input
<Matrix 4x4 (1.8334, -0.5595,  0.0113, 0.6324)
            (0.5749,  0.1069, -0.9128, 2.6868)
            (6.2012,  1.4492,  0.3085, 0.8749)
            (0.0000,  0.0000,  0.0000, 1.0000)>
Quaternion decompose
<Matrix 4x4 ( 4.5809, -1.0592, -0.1913, 0.6324)
            (-1.7931, -0.0093, -0.9261, 2.6868)
            ( 4.2364,  1.1414, -0.1851, 0.8749)
            ( 0.0000,  0.0000,  0.0000, 1.0000)>
0.6159369945526123
3 x 3 decompose
<Matrix 4x4 (1.8334, -0.5595,  0.0113, 0.6324)
            (0.5749,  0.1069, -0.9128, 2.6868)
            (6.2012,  1.4492,  0.3085, 0.8749)
            (0.0000,  0.0000,  0.0000, 1.0000)>
0.0
batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Great! The matrix approach works just as expected. But this then brings the question, given "t"(Vector), "q"(Quaternion) and "s"(Vector) (from your example), is there any way to arrive at the "input" matrix? If not the exact matrix, an equivalent one, that results in the same transform of the child object when its matrix_local set with this new equivalent matrix. Best Regards – QuantumCoderQC May 26 '21 at 17:19
  • I see, from what I gather, its better not to use the matrix_local at all. The original reason for this question was for an add-on game engine called Armory3D in Blender. This add-on exports matrix_local parameter as the local matrix of each object in the Scene. For me I find it intuitive using a matrix_local than matrix_basis, since it is very straightforward to modify and also obtain the global matrix. Hence was exploring a way to compose decompose the local matrix in a better way. – QuantumCoderQC May 27 '21 at 07:48
  • AFAIK there's no issue with exporting local matrix. The question was related to decomposing and recomposing. The "elephant in the room" is matrix_parent_inverse which if identity will be no issue. – batFINGER May 27 '21 at 08:46