# Set origin to bottom center of multiple objects

I have a lot of 3D objects of various sizes, shapes in blender 2.76b and I would like to set the origin to the bottom center of the objects bounds.

I cannot select the bottom edge and snap to cursor etc as each shapes edges are in different X/Y positions.

Is there a script or tool that will allow me to set the origin to the lowest edge z position?

• If I'm not mistaken what you're asking for is a way to set an object's pivot to the center of the bottom of its bounds in world space, is that correct? – MaVCArt Nov 25 '15 at 16:43
• Yes, that is 100% correct – MrDave Nov 25 '15 at 18:54
• – zeffii Nov 26 '15 at 13:53

Move the origin to bottom of all selected mesh objects.

import bpy
from mathutils import Vector
import bmesh

context = bpy.context

def global_origin_to_bottom(obj):
mw = obj.matrix_world

bm = bmesh.new()
bm.from_mesh(obj.data)
global_verts = [mw * Vector(v[:]) for v in obj.bound_box]
print(global_verts)

l = len(global_verts)
x = sum([v.x for v in global_verts]) / l
y = sum([v.y for v in global_verts]) / l
z = min([v.z for v in global_verts])
global_origin = Vector([x, y, z])

local_origin = mw.inverted_safe() * global_origin

for v in bm.verts:
v.co = v.co - local_origin

bm.to_mesh(obj.data)

#move the mesh back

mw.translation = global_origin

def origin_to_bottom(obj):
mw = obj.matrix_world
local_verts = [Vector(v[:]) for v in obj.bound_box]
bm = bmesh.new()
bm.from_mesh(obj.data)
x, y, z = 0, 0, 0

l = len(local_verts)
'''
# will give a modified center
# eg if array modifier will be centre of array
y = sum([v.y for v in local_verts]) / l
x = sum([v.x for v in local_verts]) / l
'''
z = min([v.z for v in local_verts])

local_origin = Vector((x, y, z))
global_origin = mw * local_origin

for v in bm.verts:
v.co = v.co - local_origin

bm.to_mesh(obj.data)

#move the mesh back

mw.translation = global_origin

#test

mesh_objs = [mo for mo in context.selected_objects if mo.type == 'MESH']
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')

for o in mesh_objs:
origin_to_bottom(o)
#global_origin_to_bottom(o)

• That doesn't work, it seems to set the origin to the center of the bounds in all axis, I need Z position to be bottom of the object bounds. – MrDave Nov 25 '15 at 18:54
• actually it seems to set the x origin position to the highest x vert position ? Strange as the code looks like it should work for lowest z?? – MrDave Nov 25 '15 at 19:08
• I'd suggest calculating the average XY and minimum Z of all the global vertex coordinates (rather than calculating it for the local coordinates, then calculating the global value only for the resulting origin), because rotations, scale, etc can give you weird results which will result with a wrong origin. – TLousky Nov 25 '15 at 19:19
• Added the origin to geometry operator as the code only worked for origins within a mesh. The position given is local (put 3d cursor in local mode) and the origin will be on minz, is your object rotated? Do you want the origin of the object to be relative to their current world position? If so perhaps adding an empty parent as a handle would be another approach – batFINGER Nov 25 '15 at 19:20
• This is very helpful for text objects. I appreciate the script! – Jeff Lange Jan 23 '17 at 18:07

This script will move the origin to the median point of the vertex/vertices with the lowest Z value (not necessarily the bottom center of the object).

Copy this script to Text window and Run Script, this will work in Edit mode and object mode, results:
1- Object mode is activated in the end result.
2- Origin set to the median point of the vertex/vertices with the lowest Z value.
4- 3D cursor is set at the new origin.

    import bpy

def select_lower_Z():

o = bpy.context.object  # active object
mw = o.matrix_world      # Active object's world matrix
glob_vertex_coordinates = [ mw * v.co for v in o.data.vertices ] # Global coordinates of vertices

bpy.ops.object.mode_set(mode = 'EDIT') #Change mode of selected object to Edit mode
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') #Set the type in Edit mode to Vertices
bpy.ops.mesh.select_all(action = 'DESELECT') #Deselect all

bpy.ops.object.mode_set(mode = 'OBJECT') #Change mode of selected object to Object mode

# Find the lowest Z value amongst the object's verts
minZ = min( [ co.z for co in glob_vertex_coordinates ] )

# Select all the vertices that are on the lowest Z
for v in o.data.vertices:
if (mw * v.co).z == minZ:
v.select = True

bpy.ops.object.mode_set(mode = 'EDIT') #Change mode of selected object to Edit mode

current_area_type = bpy.context.area.type#Save the current area type to a variable
area = bpy.context.area #Change the area to 3D view in order to get rid of wrong context error
old_type = area.type #Change the area to 3D view in order to get rid of wrong context error
area.type = 'VIEW_3D' #Change the area to 3D view in order to get rid of wrong context error
bpy.ops.view3d.snap_cursor_to_selected() #Move the cursor to selected
bpy.ops.object.mode_set(mode= 'OBJECT') #Set the mode back to Object mode
bpy.ops.object.origin_set(type='ORIGIN_CURSOR') #Move the selected object origing's to the 3D cursor's location
bpy.context.area.type = current_area_type #Set the area type back to what it was before changing it to 3D view

select_lower_Z()

• Only works for one at a time – AzulShiva May 15 '17 at 14:48
• Yes, this script is part of an add-on I was working on, the add-on now is complete, works for multiple mesh objects and has many features. Here's a link to the tutorial youtu.be/OaieiTAh5ZA the download link is in the description – Georges May 16 '17 at 16:11
• " This video is unavailable. Sorry about that." Link is dead – AzulShiva May 16 '17 at 18:42
• youtu.be/oaieiTAh5ZA – Georges May 20 '17 at 9:22