Drop to ground.
This commit is contained in:
parent
0792bd6901
commit
91fa10b970
|
@ -25,7 +25,7 @@ class Root {
|
|||
cam.world = Resource.getWorld(Main.projectScene, resource.world_ref);
|
||||
|
||||
// Physics
|
||||
physics = new PhysicsWorld();
|
||||
physics = new PhysicsWorld(resource.gravity);
|
||||
Eg.addNodeTrait(sceneNode, physics);
|
||||
|
||||
App.notifyOnRender(render);
|
||||
|
|
|
@ -32,7 +32,7 @@ class PhysicsWorld extends Trait {
|
|||
static inline var timeStep = 1 / 60;
|
||||
static inline var fixedStep = 1 / 60;
|
||||
|
||||
public function new() {
|
||||
public function new(gravity:Array<Float> = null) {
|
||||
super();
|
||||
|
||||
rbMap = new Map();
|
||||
|
@ -49,7 +49,8 @@ class PhysicsWorld extends Trait {
|
|||
var solver = BtSequentialImpulseConstraintSolver.create();
|
||||
|
||||
world = BtDiscreteDynamicsWorld.create(dispatcher, broadphase, solver, collisionConfiguration);
|
||||
world.ptr.setGravity(BtVector3.create(0, 0, -9.81).value);
|
||||
if (gravity == null) gravity = [0, 0, -9.81];
|
||||
world.ptr.setGravity(BtVector3.create(gravity[0], gravity[1], gravity[2]).value);
|
||||
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
|
|
@ -2221,6 +2221,8 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
self.ExportWorlds()
|
||||
self.output.world_ref = scene.world.name
|
||||
|
||||
self.output.gravity = [scene.gravity[0], scene.gravity[1], scene.gravity[2]]
|
||||
|
||||
self.ExportObjects(scene)
|
||||
|
||||
self.cb_postprocess()
|
||||
|
|
193
blender/lib/drop_to_ground.py
Normal file
193
blender/lib/drop_to_ground.py
Normal file
|
@ -0,0 +1,193 @@
|
|||
# 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
|
||||
|
||||
# if spherical is True:
|
||||
# e = Euler(
|
||||
# (uniform(0, math.pi * 2),
|
||||
# uniform(0, math.pi * 2),
|
||||
# uniform(0, math.pi * 2)),
|
||||
# 'XYZ')
|
||||
# mat_rot = e.to_matrix().to_4x4()
|
||||
# ground.matrix_world = mat_rot * mat_original
|
||||
|
||||
|
||||
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
|
||||
|
||||
# if spherical is True:
|
||||
# ob.matrix_world = mat_rot * ob.matrix_world
|
||||
|
||||
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)
|
|
@ -7,6 +7,7 @@ import traits_animation
|
|||
import traits_params
|
||||
import traits
|
||||
import props
|
||||
import lib.drop_to_ground
|
||||
|
||||
import bpy
|
||||
import utils
|
||||
|
@ -24,6 +25,7 @@ def register():
|
|||
traits_animation.register()
|
||||
traits_params.register()
|
||||
traits.register()
|
||||
lib.drop_to_ground.register()
|
||||
|
||||
# Start server
|
||||
user_preferences = bpy.context.user_preferences
|
||||
|
@ -45,6 +47,7 @@ def unregister():
|
|||
traits_params.unregister()
|
||||
traits.unregister()
|
||||
props.unregister()
|
||||
lib.drop_to_ground.unregister()
|
||||
|
||||
# Stop server
|
||||
register.p.terminate()
|
||||
|
|
Loading…
Reference in a new issue