My latest project requires me to place around 200 objects on a curving surface, my first thought is to use the Drop onto Ground script, however looking around 2.5 I still haven’t found it.
This is a fast script that will do something like ‘Drop onto Ground’, just change ground_object_name and select your objects… it works on z axis
ground_object_name = 'Plane'
import bpy, mathutils
from mathutils import Vector
ground = bpy.data.objects[ground_object_name]
ground.select = False
for o in bpy.context.selected_objects:
po = Vector((o.location[0],o.location[1]))
dd = 999
for f in ground.data.faces:
d = po - Vector((f.center[0],f.center[1]))
if d.length < dd:
dd = d.length
face = f
o.location[2] = face.center[2]
Hi, here is a small improvement over last script, it used to work with local values, but now it will take a ground object with spatial transformations -and even modifiers like a subsurf- and place all your selected objects over the surface. It still asumes ‘gravity’ is on your z axis…
#### snap objects to ground
ground_object_name = 'Plane'
import bpy, mathutils
from mathutils import Vector
ground = bpy.data.objects[ground_object_name]
temp = ground.to_mesh(bpy.context.scene, True, 'RENDER')
temp.transform(ground.matrix_world)
ground.select = False
for ob in bpy.context.selected_objects:
xy = Vector((ob.location[0],ob.location[1]))
dd = 999
for f in temp.faces:
d = xy - Vector((f.center[0],f.center[1]))
if d.length < dd:
dd = d.length
face = f
ob.location[2] = face.center[2]
There are 400 objects in the scene that are checked against 1024 faces of the subdivided plane, that is why it takes some time… just reduce plane subdivisions. Anyway 10 seconds is faster than doing it by hand
It is a very simple script though, maybe it could be done with blender geometry module…?
And other question, how to easily traslate face normal to object rotation, ‘ob.rotation_euler = face.normal’ doesn’t seem to work…
have fun
edit: for now I will stick to: ob.rotation_euler.rotate(face.normal.to_track_quat(‘Z’,‘Y’)) to get objects rotated according to face normals… it is a oneliner but far from perfect
Ricky just wanted a single line way of orienting objects according to face normal vectors, this seems to work ok in the posted blend but any help that doesn’t involve struggling with matrices is welcome
ground_object_name = 'Plane'
rotate = False
import bpy, mathutils
from mathutils import Vector
ground = bpy.data.objects[ground_object_name]
temp = ground.to_mesh(bpy.context.scene, True, 'RENDER')
temp.transform(ground.matrix_world)
ground.select = False
for ob in bpy.context.selected_objects:
xy = Vector((ob.location[0],ob.location[1]))
dd = 999
for f in temp.faces:
d = xy - Vector((f.center[0],f.center[1]))
if d.length < dd:
dd = d.length
face = f
ob.location[2] = face.center[2]
if rotate:
ob.rotation_mode = 'QUATERNION'
ob.rotation_quaternion = face.normal.to_track_quat('Z','Y')
ob.rotation_mode = 'XYZ'
I need to do just that too. Except I’m not familiar enough with the scripting part of Blender
Can anyone please explain how to use this script? Unfortunately googling “Blender 2.5, how to run a script” didn’t bring me much help at all
hi, you need a text editor window to run a script, you can modify your layout from Default to Scripting from info bar on top, or change any window to a text editor with shift+F11
so, paste the text there and edit it, change ‘Plane’ to the name of your ground object, if you want objects to orient to fit face normals set rotate to True… select your objects and press the run script button
you can also add a subsurf to the ground to get better results, then just remove it
see that I just slighty modified the script above, so run this one…
my mesh didn’t have the attribute ‘faces’ but ‘polygons’
I got an error for the part & lt ; dd: so I changed it to " < dd: "
It works for my case, but also make sure the pivot point of your objects is at the bottom, or otherwise you have to move all objects up a bit afterwards
#### snap objects to ground
ground_object_name = 'Plane'
import bpy, mathutils
from mathutils import Vector
ground = bpy.data.objects[ground_object_name]
temp = ground.to_mesh(bpy.context.scene, True, 'RENDER')
temp.transform(ground.matrix_world)
ground.select = False
for ob in bpy.context.selected_objects:
xy = Vector((ob.location[0],ob.location[1]))
dd = 999
for f in temp.polygons:
d = xy - Vector((f.center[0],f.center[1]))
if d.length < dd:
dd = d.length
face = f
ob.location[2] = face.center[2]