14
$\begingroup$

Read through a lot of questions but I didn't find a simple answer.

How do I move an object on it's local axis using a vector? I don't want to use bpy.ops.transform.translate, because it's slow.

Given an object that is rotated and an example vector (1,2,3). How can I do a translation on the local axis, so the object is moved 1 on it's local x-axis, 2 on the local y-axis, 3 on the local z-axis. Just like in the viewport, when you move an object pressing "g" and then pressing the x-axis key (or y / z) twice.

EDIT: So from a C++ post I understand the math behind it, still I'm unable to reproduce it in Blender. For the local translation T you have to do the translation first, then multiply it with the rotation matrix R. So (pseudocode)

myobject.location = T(1,2,3) * R

Problems: 1.) How do I get R of the object that is already rotated. 2.) Can I just multiply a vector with that matrix? 3.) What about the location that the object had before? Just add it?

$\endgroup$

4 Answers 4

15
$\begingroup$

This seems to work the inverse of the world matrix is used to align the translation vector to the local axis:

import bpy
import mathutils

cube = bpy.data.objects["Cube"]
# one blender unit in x-direction
vec = mathutils.Vector((1.0, 0.0, 0.0))
inv = cube.matrix_world.copy()
inv.invert()
# vec aligned to local axis in Blender 2.8+
# in previous versions: vec_rot = vec * inv
vec_rot = vec @ inv
cube.location = cube.location + vec_rot
$\endgroup$
5
  • $\begingroup$ Thanks you Sir! For completeness, this works also in a condensed form: cube.location += vec * inv. $\endgroup$
    – bortran
    Commented Mar 9, 2015 at 11:02
  • 1
    $\begingroup$ This fails if the object is scaled. Using cube.rotation_euler.to_matrix() as invmatrix seems to be better $\endgroup$
    – florian h
    Commented Oct 3, 2018 at 16:34
  • $\begingroup$ Running this code as of Blender 2.82 gives and error TypeError: Element-wise multiplication: not supported between 'Vector' and 'Matrix' types $\endgroup$ Commented Feb 19, 2020 at 3:26
  • 1
    $\begingroup$ For Blender 2.8+, the operator @ should be use instead of *. See blender.stackexchange.com/questions/129473/… $\endgroup$
    – oktomus
    Commented Jul 10, 2020 at 18:22
  • $\begingroup$ The answer is correct but note that most of the time, the most practical is to set the parenting of objects before hand, depending on what you try to do. Example, moving a pixel perfect sprite always parallel to the camera. This produces something similar to a 2D overlay in front of the 3D scene, if you place them very close to the near clipping plane. You can use this math, or you can simply parent your objects to the camera, then just change sprite.location.x and sprite.location.y. Tested. $\endgroup$ Commented Jun 11, 2021 at 2:35
6
$\begingroup$

In order to make it faster you could also assign the values directly to the location property:

import bpy
import mathutils

# get the object
obj = bpy.data.objects["Object"]

# store the current location
loc = obj.location

# adjustment values
(x,y,z) = (1.0,2.0,3.0)

# adding adjustment values to the property
obj.location = loc + mathutils.Vector((x,y,z))

Assigning and adding the values in one line:

bpy.data.objects["Object"].location = bpy.data.objects['Object'].location + Vector((x,y,z))

Simple and fast is adding the adjustment values to each axis:

bpy.data.objects["Object"].location.x += 1.0
bpy.data.objects["Object"].location.y += 2.0
bpy.data.objects["Object"].location.z += 3.0
$\endgroup$
3
  • 4
    $\begingroup$ But that's a global translation. $\endgroup$
    – bortran
    Commented Mar 9, 2015 at 9:05
  • 1
    $\begingroup$ It's not a global translation. An object with ob.location = (0, 0, 0) can be placed anywhere in the scene using constraints or parenting. There is only one global origin. $\endgroup$
    – batFINGER
    Commented Nov 15, 2019 at 11:41
  • $\begingroup$ This answer is also correct. It is not a global translation if you plan your scene beforehand. Example, parent your objects to the camera, then object.location, in scripts, will move parallel to the camera plane if they had the same rotation at the time of parenting, or you apply rotation after parenting. This guarantee two axis will be parallel to the camera plane. It depends of how you oriented your object's mesh, and of non applied transformations before parenting, but they are usually [x,y] and z will move closer or away from the camera plane. $\endgroup$ Commented Jun 11, 2021 at 2:45
2
$\begingroup$

Try this blender 2.8 script to displace all cylinders in a scene, with respect to their axis in the -ve Z direction:

        if obj.name.startswith('Cylinder'):

      # print(obj.location)

      # one blender unit in x-direction
        distz = mathutils.Vector((0.0, 0.0, -0.001))
        rotationMAT = obj.rotation_euler.to_matrix()
        rotationMAT.invert()
        # project the vector to the world using the rotation matrix
        zVector = distz @ rotationMAT
        obj.location = obj.location + zVector
$\endgroup$
1
  • $\begingroup$ This is what works in 2020! $\endgroup$
    – bogl
    Commented Apr 13, 2020 at 12:33
1
$\begingroup$

So I made this now, but I don't know if it's correct.

import bpy
import mathutils
from mathutils import Vector, Matrix

myobject = bpy.context.active_object
rotMat = myobject.rotation_euler.to_matrix()
pos = myobject.location
newPos = Vector([1, 2, 3])
myobject.location = newPos * rotMat + pos
$\endgroup$

You must log in to answer this question.

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