1
$\begingroup$

I have to create boxes, cylinders and spheres, to scale them and to rototranslate them in space by using a matrix transform. This is the code for a box:

myObj_TR = Matrix((
    (1, 0, 0, 0),
    (0, 0.707, 0.707, 0),
    (0, -0.707, 0.707, 0),
    (1, 0, 0, 1)))

bpy.ops.mesh.primitive_cube_add()
bpy.ops.transform.resize(value=(1,2,.3))

myObj = bpy.context.object
myObj.data.transform(myObj_TR)
myObj.data.update()

The problem is that in this way the box results sheared; it seems that the scaling is actually applied after the rototranslation.

I think that a workaround should be parenting my objects and then rototranslate the parent. Are there alternative ways?

Thank you

$\endgroup$
2
$\begingroup$

You are applying transformation at object level with bpy.ops.transform.resize() and on data level with myObj.data.transform(). The data transform is directly applied to vertices. The vertices' position simply is updated and the transformation is lost. When applying the transformation to the object the matrix is stored (if possible) in the translation, rotation and scale properties of the object. The object transform is applied on the vertex positions. In your case this results in objMatrix @ dataMatrix or scaleMatrix @ locrotMatrix.

You want to swap that order. I would advise you to either apply the transformation to the object or the data.

You can construct the final matrix separately first.

import bpy
from mathutils import Matrix

mat_rot = Matrix([[1,  0,     0,     0],
                  [0,  0.707, 0.707, 0],
                  [0, -0.707, 0.707, 0],
                  [1,  0,     0,     1]])

mat_scale = Matrix([[1, 0, 0, 0],
                    [0, 2, 0, 0],
                    [0, 0, 3, 0],
                    [0, 0, 0, 1]])

mat = mat_rot @ mat_scale

If you want to apply this matrix at the object level, use object.matrix_world.

bpy.ops.mesh.primitive_cube_add()
myObj = bpy.context.object
myObj.matrix_world = mat

If you want to apply this matrix at the data level, use data.transform().

bpy.ops.mesh.primitive_cube_add()
myObj = bpy.context.object
myObj.data.transform(mat)

From the comments: If you don't import your matrix, but are constructing them from scratch, use the Helper constructors from the Matrix class, such as Matrix.Diagonal or Matrix.Rotation

$\endgroup$
  • $\begingroup$ Worth noting: bpy.ops.transform... applies on a data level when in edit mode. (on selected geometry). There are nice constructors for matrices eg R = Matrix.Rotation(radians(45), 4, 'X') and S = Matrix.Diagonal((1, 2, 0.3)).to_4x4() note element 3,3 in scale matrix is 1, not 0, could create complications $\endgroup$ – batFINGER Nov 8 '19 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for?Browse other questions tagged or ask your own question.