11
$\begingroup$

I have a lot of objects. I need to translate every vertex of every object by an offset, without moving the objects origin. For a single object, I can do this Tabbing into Edit Mode, selecting all with A, and then translating with G. I would have to repeat this for every object.

If I select every object in Object Mode, I can translate everything with G, but the transform is not applied to just vertices; it moves the origin, too. I need this to export the mesh with Ogre exporter.

$\endgroup$

3 Answers 3

4
$\begingroup$

After placing the objects you can Apply Transform:

Object -> Apply -> Location.

Note that the Exporter should handle this and you could report a bug to the author.

So far the answers here have focused on how to do this from Python, but Im not sure why that is, the question isn't asking about scripting and there is a tool handle this.

$\endgroup$
3
  • $\begingroup$ why focus on a python solution? maybe to provide general solutions that could apply in more scenarios than just the question description. The title might attract different use cases. $\endgroup$
    – zeffii
    Commented Jun 15, 2013 at 5:19
  • $\begingroup$ @zeffi, I don't think we should be giving answers that involve knowing Python unless its not possible from the default tool-set. $\endgroup$
    – ideasman42
    Commented Jun 16, 2013 at 1:30
  • $\begingroup$ This is really what I was looking for! Just so simple... $\endgroup$ Commented Jun 17, 2013 at 7:51
5
$\begingroup$

This might not be the best solution, but being a developer I can't resist myself from posting this answer... :-)

Open console and type following:

# Move mesh vertices without affecting its origin
def move_by_amount(x, y, z, only_selected=True): # Default is True
    if only_selected:
        meshes = (obj.data for obj in bpy.context.selected_objects if obj.type == 'MESH')
    else:
        meshes = bpy.data.meshes
    for mesh in meshes: # We move selected/all meshes
        for vertex in mesh.vertices:
            vertex.co += Vector((x, y, z)) # See comments

# Replace with your own x, y, z coordinates
move_by_amount(10, -15, 5, True) # True to move only selected objects
move_by_amount(10, -15, 5, False) # False to move all objects
move_by_amount(10, -15, 5) # Default is True to move only selected objects

This has at least passed a basic test with few cubes without changing origins. Please test with your data. You can always undo if things go wrong! ;-)

$\endgroup$
7
  • 1
    $\begingroup$ Even if zeffii's solution works, this function solution is more elegant. $\endgroup$ Commented Jun 14, 2013 at 17:13
  • $\begingroup$ @zeffii yes.. I've already written that in comment. But we can add one more simple for loop in exchange of simplicity... :-) $\endgroup$
    – mg007
    Commented Jun 14, 2013 at 18:22
  • 1
    $\begingroup$ Suggest to += a Vector() rather then x,y,z - which will be slower because of multiple attribute access and internal update functions. $\endgroup$
    – ideasman42
    Commented Jun 15, 2013 at 0:35
  • $\begingroup$ Also note, typically you wont want to access all meshes in a blend file, so useful for an example but if you write a tool, use visible/selected objects from the context. $\endgroup$
    – ideasman42
    Commented Jun 15, 2013 at 0:43
  • $\begingroup$ @ideasman42 Thanks for feedback. Just compared with Vector() solution with timeit, but the total difference is not more than 0.02 sec (for mesh having over 100K vertices, so about .2 microsec per vertex). And I say difference because in some (few) cases this solution is faster (by negligible amount). So I'll keep it as it is and add a comment regarding this. $\endgroup$
    – mg007
    Commented Jun 15, 2013 at 4:32
4
$\begingroup$

Heres a solution that avoids accessing verts one at a time.

Theres also the gotcha that an object may share mesh data, so you wont want to transform these more then once (thats why its using a set).

import bpy

def move_by_amount(x, y, z):
    from mathutils import Matrix
    matrix = Matrix.Translation((x, y, z))
    mesh_unique = set(obj.data for obj in bpy.context.selected_objects)
    for mesh in mesh_unique:
        mesh.transform(matrix)
        mesh.update()

# Replace with your own x, y, z coordinates
move_by_amount(10, -15, 5)
$\endgroup$
2
  • $\begingroup$ I like this one way more than my solution, which i will delete now. Definitely good to encourage the use of Matrix :) $\endgroup$
    – zeffii
    Commented Jun 15, 2013 at 4:56
  • $\begingroup$ Well... this applies to me too... I recommend OP to select this instead of mine :) I learnt about Mesh.transform. $\endgroup$
    – mg007
    Commented Jun 15, 2013 at 5:39

You must log in to answer this question.

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