# http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Object/Drop_to_ground import bpy from bpy.props import * import bmesh from random import seed, uniform import math import mathutils from mathutils import * def transform_ground_to_world(sc, ground): tmpMesh = ground.to_mesh(sc, True, 'PREVIEW') tmpMesh.transform(ground.matrix_world) tmp_ground = bpy.data.objects.new('tmpGround', tmpMesh) sc.objects.link(tmp_ground) sc.update() return tmp_ground def get_lowest_world_co_from_mesh(ob, mat_parent=None): bme = bmesh.new() bme.from_mesh(ob.data) mat_to_world = ob.matrix_world.copy() if mat_parent: mat_to_world = mat_parent * mat_to_world lowest = None # bme.verts.index_update() for v in bme.verts: if not lowest: lowest = v if (mat_to_world * v.co).z < (mat_to_world * lowest.co).z: lowest = v lowest_co = mat_to_world * lowest.co bme.free() return lowest_co def drop_objects(self, context, ground, obs, use_origin, offset, drop_random): # Random distribution if drop_random: halfX = ground.dimensions.x / 2 halfY = ground.dimensions.y / 2 for ob in obs: # if spherical is True: # ob.matrix_world = Matrix.Translation((0, 0, 100)) # else: ob.location = ( ground.location.x + uniform(-halfX, halfX), ground.location.y + uniform(-halfY, halfY), ground.location.z + 1000) # if spherical is True: # ground.matrix_world.translation = ((0, 0, 0)) tmp_ground = transform_ground_to_world(context.scene, ground) down = Vector((0, 0, -10000)) mat_original = ground.matrix_world.copy() for ob in obs: if use_origin: lowest_world_co = ob.location else: lowest_world_co = get_lowest_world_co_from_mesh(ob) if not lowest_world_co: continue was_hit, hit_location, hit_normal, hit_index = \ tmp_ground.ray_cast(lowest_world_co, lowest_world_co + down) if hit_index is -1: continue to_ground_vec = hit_location - lowest_world_co ob.matrix_world *= Matrix.Translation(to_ground_vec) ob.location.z += offset ground.matrix_world = mat_original bpy.ops.object.select_all(action='DESELECT') tmp_ground.select = True bpy.ops.object.delete('EXEC_DEFAULT') for ob in obs: ob.select = True ground.select = True bpy.context.scene.objects.active = ground class OBJECT_OT_drop_to_ground(bpy.types.Operator): bl_idname = "object.drop_on_active" bl_label = "Drop to Ground" bl_options = {'REGISTER', 'UNDO'} bl_description = "Drop selected objects on active object" use_origin = BoolProperty( name="Use Center", description="Drop to objects origins", default=False) drop_random = BoolProperty( name="Random", description="Drop to random point", default=False) offset = FloatProperty( name="Margin", description="Offset from the ground", default=0.0) @classmethod def poll(cls, context): return len(context.selected_objects) >= 2 def execute(self, context): ground = context.object obs = context.selected_objects obs.remove(ground) drop_objects(self, context, ground, obs, self.use_origin, self.offset, self.drop_random) return {'FINISHED'} # http://blenderartists.org/forum/showthread.php?229346-AddOn-Duplicate-Multiple-Linked def duplicate_object(context, numCopies, transVec, doParent): activeObj = context.active_object dupCopies = [] dupCopies.append(activeObj) while numCopies > 0: bpy.ops.object.duplicate_move_linked(OBJECT_OT_duplicate={"linked":True, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":transVec, "release_confirm":False}) dupCopies.append(context.active_object) numCopies -= 1 if doParent: groupName = activeObj.name + "_Copies" bpy.ops.object.add(type='EMPTY') groupEmpty = context.active_object groupEmpty.name = groupName for i in dupCopies: bpy.data.objects[i.name].select = True bpy.data.objects[groupEmpty.name].select = True bpy.ops.object.parent_set(type="OBJECT") else: for i in dupCopies: bpy.data.objects[i.name].select = True class OBJECT_OT_multi_duplicate(bpy.types.Operator): bl_idname = "object.multi_duplicate" bl_label = "Duplicate Multiple Linked" bl_options = {"REGISTER", "UNDO"} num_copies = bpy.props.IntProperty(name="Number of Copies:", default=1, description="Number of copies", min=1, max=5000, subtype="NONE") xyz_offset = bpy.props.FloatVectorProperty(name="XYZ Offset:", default=(0.0,0.0,0.0), min=-1000, max=1000, description="XYZ Offset") do_parent = bpy.props.BoolProperty(name="Parent under Empty", default=True) @classmethod def poll(cls, context): ob = context.object if ob == None: return False elif ob.select: return True return False def execute(self, context): duplicate_object(context, self.num_copies, self.xyz_offset, self.do_parent) return {'FINISHED'} def invoke(self, context, event): return self.execute(context) class ArmToolsPanel(bpy.types.Panel): bl_label = "Armory Tools" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" def draw(self, context): self.layout.operator("object.drop_on_active") self.layout.operator("object.multi_duplicate") def register(): bpy.utils.register_class(OBJECT_OT_drop_to_ground) bpy.utils.register_class(OBJECT_OT_multi_duplicate) bpy.utils.register_class(ArmToolsPanel) def unregister(): bpy.utils.unregister_class(OBJECT_OT_drop_to_ground) bpy.utils.unregister_class(OBJECT_OT_multi_duplicate) bpy.utils.unregister_class(ArmToolsPanel)