# How to place any object on the 'floor' of a scene?

I added a cylinder to my scene, rotated, resized, like this:

I moved it up, because I want to make a model from this and I want it to stand on the ground:

I zoomed in and learned, that this object is not on the grid floor, it floats above it:

My question is: how can I put any object on the floor? (Yes, right, I could move it up half it's size, but think on more complex objects, like a terrain.)

You could select a vertex, edge or face in Edit Mode and snap the 3D cursor to the selection Shift-S Cursor to Selection

In object mode set the object origin to 3D-cursor.

After that you can easily position the object to the 3D cursors position which can be adjusted in the proerties panel.

Followed by Snap Shift-S Selection to Cursor

• Move the cursor to selection, move the object origin to cursor, then move object so it's origin is at Z zero. Makes perfect sense. So why do you then say "Snap Selection to Cursor" which undoes what you just did? The 3D cursor is still where it was when you moved it to the selected geometry with "Cursor to Selection". So why would you want to move the object back to the 3D cursor? Sep 1 at 1:18

The script posted earlier is overkill IMHO, and inefficient. The following is all you need. This doesn't mess with object origins and doesn't require you to apply rotations. No need for bmesh either.

import bpy
context = bpy.context

for obj in context.selected_objects:
mx = obj.matrix_world
minz = min((mx @ v.co)[2] for v in obj.data.vertices)
mx.translation.z -= minz

• Oh, very interesting @ mx.translation, thanks! Aug 29 '18 at 18:44
• Done, thanks. I've also removed the list comprehension. Aug 31 '18 at 10:13
• Thankyou. Prefer (mx * v.co).z but that is only aesthetics. IMO simplest answer to implement, and best answer here. Hopefully someone else will upvote too. Aug 31 '18 at 15:41
• How to integrate these python code into blender as a button? Oct 19 '18 at 8:58
• Where do you want the button? Oct 20 '18 at 11:44

The smaller script posted by MACHIN3 is perfect, however blender 2.8x has changed the way it multiplies matrices and you now need to use the @ symbl instead of * or you will get:

TypeError: Element-wise multiplication: not supported between 'Matrix' and 'Vector'

import bpy
context = bpy.context

for obj in context.selected_objects:
mx = obj.matrix_world
minz = min((mx @ v.co)[2] for v in obj.data.vertices)
mx.translation.z -= minz


I would comment on the solution but I don't have enough reputation :(

• Welcome to BSE. Not a fan of 1 character edits becoming new answers. Soon you will have rep required to make a suggested edit, comment or upvote. Mar 21 '20 at 12:25
• @SeanPuller Could you delete this duplicate answer, now that the change you mentioned has been integrated into MACHIN3's entry? Apr 25 at 23:41

Surely the simplest method is to use Rigid Body physics sim. Simply set the 'floor' as Passive and the object as Active and then run the simulation. The object will fall (assuming you haven't messed with gravity) until it comes to rest naturally on the floor.

Once your object has settled into position, stop the animation, select it and press Ctrl+A and select 'Visual Transform' to apply the current location and rotation to the object. You can then safely remove the rigid body physics if no longer required.

Normally I just rotate and translate it into position manually (perhaps with snapping), which is good enough in most cases.

There is also an addon bundled with blender called Drop to ground which is useful for placing one or many objects on a ground object quickly.

To use it, enable it ⎈ Ctrl⎇ AltU> User preferences > addons > Drop to Ground. Now you'll have a Drop to Ground button in 3D view > Tool Shelf (T) > Addons tab > Drop to Ground.

• It is not possible to "enable" that py, because of an error: attributeError: RNA_Types object has no attribute VIEW3D_PT_tools_objectmode. :( Jan 8 '15 at 11:09
• I also tried snapping. This did not work in this case, because there was no other object on the scene. Will check with a plane as floor too. Jan 8 '15 at 11:13
• You can also use dynamics to do this. Make the ground a passive physics object. Set the other objects to be active. Now run the animation and everything should fall to the ground. There's a bit more to it than that if you want things to stay where they are when the timeline moves but to start you off that should work. Jan 8 '15 at 12:57
• Using Blender 2.7.6, I was able to fix the RNA_Types error by changing bpy.types.VIEW3D_PT_tools_objectmode to bpy.types.VIEW3D_PT_tools_object. I put the fixed code in a Gist. Oct 25 '15 at 0:40

You'll need this script:

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)


Save it as a txt file. Open the txt file with Blender Script Editor, select your objects and hit "Run Script".

Make sure to apply Rotation to the objects first if you have rotated them. Rotation X, Y and Z should be zero.

If not select your objects, press Ctrl + A and select Rotation.

To set all these objects to a specific Location Alt + Click into the Location Value, type your desired value and hit enter.

If you want to move the objects to the height of a different object you can snap your cursor to other Vertices or Objects and copy the location of your 3D Cursor to your objects that you wish to move.

If you use it as often as I do save it into your start-up file. Right click on the Menu Bar of the Text Editor, select collapse menus and tuck it away to the side like I did:

Placing an object on the ground.

• In Edit Mode select the bottom vertex, edge or face.
• From the ShiftS menu, choose 'Cursor to Selected'.
• In Object Mode, ShiftCtrlAltC, 'Set Origin to Cursor'
• Still in Object Mode, in the properties region of the 3D View (toggled by N,) in the 'Transform' panel, set Location Z to 0.

This is my Addon, based on the MACHIN3 code, the help of many people and a lot of research. Issues: only works on objects with vertices, surely it will have many programming flaws, an apology for that. However it seems to work properly with its limitations

bl_info = {
"name": "Aterrizar",
"author": "Flobo02",
"version": (1, 0),
"blender": (2, 80, 0),
"location": "View3D > Object > Snap",
"description": "Move object to floor",
"warning": "",
"wiki_url": "",
"category": "Object",
}

import bpy

#funcion
def main(context):
for obj in context.selected_objects:
mx = obj.matrix_world
minz = min((mx @ v.co)[2] for v in obj.data.vertices)
mx.translation.z -= minz
class ATERRIZAR(bpy.types.Operator):

bl_idname = "snap.aterrizar"
bl_label = "Aterrizar"

@classmethod
def poll(cls, context):
return context.active_object is not None

def execute(self, context):
main(context)
return {'FINISHED'}
#boton
def boton(self, context):
self.layout.operator(
ATERRIZAR.bl_idname,
text="To floor",
icon='TRIA_DOWN_BAR')

# ubicacion
bpy.types.VIEW3D_MT_snap.append(boton)

def register():
bpy.utils.register_class(ATERRIZAR)

def unregister():
bpy.utils.unregister_class(ATERRIZAR)

if __name__ == "__main__":
register()


test in Blender 2.82a

I don't have enough reputation to comment. But flobo2's addon has an indentation error on line 29. Just add four spaces at the beginning of that line, and you're good.

It's really handy.

Here's the fixed code, if you're too lazy to add the spaces yourself.

bl_info = {
"name": "Aterrizar",
"author": "Flobo02",
"version": (1, 0),
"blender": (2, 80, 0),
"location": "View3D > Object > Snap",
"description": "Move object to floor",
"warning": "",
"wiki_url": "",
"category": "Object",
}

import bpy

#funcion
def main(context):
for obj in context.selected_objects:
mx = obj.matrix_world
minz = min((mx @ v.co)[2] for v in obj.data.vertices)
mx.translation.z -= minz
class ATERRIZAR(bpy.types.Operator):

bl_idname = "snap.aterrizar"
bl_label = "Aterrizar"

@classmethod
def poll(cls, context):
return context.active_object is not None

def execute(self, context):
main(context)
return {'FINISHED'}
#boton
def boton(self, context):
self.layout.operator(
ATERRIZAR.bl_idname,
text="To floor",
icon='TRIA_DOWN_BAR')

# ubicacion
bpy.types.VIEW3D_MT_snap.append(boton)

def register():
bpy.utils.register_class(ATERRIZAR)

def unregister():
bpy.utils.unregister_class(ATERRIZAR)

if __name__ == "__main__":
register()

• I've made this change for you, thanks. For future reference I think you can propose an edit to a post and one of us can approve it. Jan 17 at 2:14

The answer by @MACHIN3 is good, but I disliked how it would snap each object individually to the ground, instead of snapping the whole selected group to the ground (ie. a shared offset amount).

For this "group shift" functionality, I used this code:

import bpy
context = bpy.context

minz = min(min((obj2.matrix_world @ v.co).z for v in obj2.data.vertices) for obj2 in context.selected_objects)
for obj in context.selected_objects:
obj.matrix_world.translation.z -= minz