Skip to content

Commit

Permalink
script: drop on surface
Browse files Browse the repository at this point in the history
  • Loading branch information
atticus-lv committed Apr 18, 2024
1 parent 850ee73 commit 2801091
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
3 changes: 2 additions & 1 deletion asset/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"bl_file_extensions": ".obj",
"poll_area": "VIEW_3D",
"operator_context": "EXEC_DEFAULT",
"foreach_post_script": "addCollection.py;printArgs.py;drop2floor.py;alignAxisX.py"
"foreach_post_script": "addCollection.py;printArgs.py",
"post_script": "dropOnSurface.py"
},
"Import Image Nodes": {
"bl_file_extensions": ".png;.jpg",
Expand Down
30 changes: 30 additions & 0 deletions asset/scripts/post_script/dropOnSurface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import bpy
from mathutils import Vector
from cdi_tool.boundingBox import ObjectBoundingBox, ObjectsBoundingBox, C_OBJECT_TYPE_HAS_BBOX
from cdi_tool.emptyParent import create_tmp_parent, apply_tmp_parent, align_obj2normal
from cdi_tool.raycast import ray_cast, exclude_ray_cast

event = globals().get('event')

selected_objs = [obj for obj in bpy.context.selected_objects if obj.type in C_OBJECT_TYPE_HAS_BBOX]
bboxs = [ObjectBoundingBox(obj, is_local=False) for obj in selected_objs]

if len(bboxs) != 0:
objs_A = ObjectsBoundingBox(bboxs)
bottom = objs_A.get_bottom_center()
normal = Vector((0, 0, 1))
tmp_parent = create_tmp_parent(bottom, selected_objs)
bpy.context.view_layer.depsgraph.update()

with exclude_ray_cast(selected_objs):
result, target_obj, view_point, world_loc, normal, location, matrix = ray_cast(bpy.context, event)
if result:
normal = normal.normalized()
world_loc = location
# update deps
bpy.context.view_layer.depsgraph.update()
tmp_parent.location = world_loc
bpy.context.view_layer.depsgraph.update()
align_obj2normal(normal=normal, obj=tmp_parent)

apply_tmp_parent(tmp_parent, selected_objs)
92 changes: 92 additions & 0 deletions modules/cdi_tool/emptyParent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import bpy
from mathutils import Vector


def create_tmp_parent(bottom_loc: Vector, selected_objs: list[bpy.types.Object], axis='Z',
invert_axis: bool = False)->bpy.types.Object:
offset = 0.001
if invert_axis: offset = -offset

empty = bpy.data.objects.new('Empty', None)
empty.name = 'TMP_PARENT'
empty.empty_display_type = 'PLAIN_AXES'
empty.empty_display_size = 0
empty.location = bottom_loc
z = getattr(empty.location, axis.lower())
setattr(empty.location, axis.lower(), z - offset)

rot_obj = bpy.context.object
empty.rotation_euler = rot_obj.rotation_euler

def create_tmp_parent(obj):
con = obj.constraints.new('CHILD_OF')
con.name = 'TMP_PARENT'
con.use_rotation_x = True
con.use_rotation_y = True
con.use_rotation_z = True
con.target = empty
obj.select_set(False)

for obj in selected_objs:
if obj.parent and obj.parent in selected_objs:
obj.select_set(False)
continue
# loop over the constraints in each object
create_tmp_parent(obj)
# if obj is not mesh
if rot_obj not in selected_objs:
create_tmp_parent(rot_obj)
rot_obj.select_set(True)

bpy.context.collection.objects.link(empty)
bpy.context.view_layer.objects.active = rot_obj
return empty


def apply_tmp_parent(tmp_parent: bpy.types.Object, selected_objs: list[bpy.types.Object]):
if not tmp_parent: return

# apply constraints
def apply_const(obj):
obj.select_set(True)
tmp_mx = obj.matrix_world.copy()
for con in obj.constraints:
if con.name == 'TMP_PARENT' and con.type == 'CHILD_OF':
obj.constraints.remove(con)

obj.matrix_world = tmp_mx

for obj in selected_objs:
apply_const(obj)

if bpy.context.object not in selected_objs:
apply_const(bpy.context.object)

# remove empty
bpy.data.objects.remove(tmp_parent)


def align_obj2normal(normal: Vector, obj: bpy.types.Object, axis: str = 'Z', invert_axis=False):
"""清除除了local z以外轴向的旋转"""
v = -1 if invert_axis else 1
if axis == 'Z':
z = Vector((0, 0, v))
elif axis == 'Y':
z = Vector((0, v, 0))
else:
z = Vector((v, 0, 0))

rotate_clear = obj.matrix_local.to_quaternion()

for a in ['x', 'y', 'z']:
if a == axis.lower(): continue
# clear
setattr(rotate_clear, a, 0)

rotate_clear = rotate_clear.to_matrix()
try:
offset_q = z.rotation_difference(normal)
except:
offset_q = Vector((0, 0, 1)).rotation_difference(z)

obj.rotation_euler = (offset_q.to_matrix() @ rotate_clear).to_euler()

0 comments on commit 2801091

Please sign in to comment.