14

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?

bortran
  • 1,362
  • 1
  • 14
  • 27

4 Answers4

14

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

oktomus
  • 113
  • 5
stacker
  • 38,549
  • 31
  • 141
  • 243
  • Thanks you Sir! For completeness, this works also in a condensed form: cube.location += vec * inv. – bortran Mar 09 '15 at 11:02
  • 1
    This fails if the object is scaled. Using cube.rotation_euler.to_matrix() as invmatrix seems to be better – florian h Oct 03 '18 at 16:34
  • Running this code as of Blender 2.82 gives and error TypeError: Element-wise multiplication: not supported between 'Vector' and 'Matrix' types – Reuben Tilahun Feb 19 '20 at 03:26
  • 1
    For Blender 2.8+, the operator @ should be use instead of *. See https://blender.stackexchange.com/questions/129473/typeerror-element-wise-multiplication-not-supported-between-matrix-and-vect – oktomus Jul 10 '20 at 18:22
  • 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. – Hatoru Hansou Jun 11 '21 at 02:35
6

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
p2or
  • 15,860
  • 10
  • 83
  • 143
Giorgi Bakhtadze
  • 449
  • 1
  • 3
  • 8
  • 4
    But that's a global translation. – bortran Mar 09 '15 at 09:05
  • 1
    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. – batFINGER Nov 15 '19 at 11:41
  • 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. – Hatoru Hansou Jun 11 '21 at 02:45
2

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
Moog
  • 2,202
  • 13
  • 17
Karim Sherif
  • 123
  • 2
1

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
bortran
  • 1,362
  • 1
  • 14
  • 27