-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
850ee73
commit 2801091
Showing
3 changed files
with
124 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |