Add Lattice Magic
to Addons
#48
@ -134,10 +134,10 @@ class TWEAKLAT_OT_Create(bpy.types.Operator):
|
|||||||
max=64
|
max=64
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Add an option to spawn at the location of the parent (object or bone).
|
|
||||||
location: EnumProperty(name="Location", items=[
|
location: EnumProperty(name="Location", items=[
|
||||||
('CURSOR', "3D Cursor", "Create at the location and orientation of the 3D cursor.")
|
('CURSOR', "3D Cursor", "Create at the location and orientation of the 3D cursor.")
|
||||||
,('CENTER', "Center", "Create at the bounding box center of all selected objects.")
|
,('CENTER', "Center", "Create at the bounding box center of all selected objects.")
|
||||||
|
,('PARENT', "Parent", "Create at the location of the parent object or bone.")
|
||||||
])
|
])
|
||||||
radius: FloatProperty(
|
radius: FloatProperty(
|
||||||
name="Radius",
|
name="Radius",
|
||||||
@ -161,6 +161,10 @@ class TWEAKLAT_OT_Create(bpy.types.Operator):
|
|||||||
for m in parent_obj.modifiers:
|
for m in parent_obj.modifiers:
|
||||||
if m.type == 'ARMATURE' and m.object:
|
if m.type == 'ARMATURE' and m.object:
|
||||||
parent_obj = m.object
|
parent_obj = m.object
|
||||||
|
if self.parent_bone not in parent_obj.data.bones:
|
||||||
|
self.parent_bone = ""
|
||||||
|
break
|
||||||
|
|
||||||
context.scene.tweak_lattice_parent_ob = parent_obj
|
context.scene.tweak_lattice_parent_ob = parent_obj
|
||||||
|
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@ -237,8 +241,13 @@ class TWEAKLAT_OT_Create(bpy.types.Operator):
|
|||||||
if self.location == 'CENTER':
|
if self.location == 'CENTER':
|
||||||
meshes = [o for o in context.selected_objects if o.type=='MESH']
|
meshes = [o for o in context.selected_objects if o.type=='MESH']
|
||||||
root.matrix_world.translation = bounding_box_center_of_objects(meshes)
|
root.matrix_world.translation = bounding_box_center_of_objects(meshes)
|
||||||
else:
|
elif self.location == 'CURSOR':
|
||||||
root.matrix_world = context.scene.cursor.matrix
|
root.matrix_world = context.scene.cursor.matrix
|
||||||
|
elif self.location == 'PARENT':
|
||||||
|
matrix_of_parent = scene.tweak_lattice_parent_ob.matrix_world
|
||||||
|
if self.parent_bone:
|
||||||
|
matrix_of_parent = scene.tweak_lattice_parent_ob.matrix_world @ scene.tweak_lattice_parent_ob.pose.bones[self.parent_bone].matrix
|
||||||
|
root.matrix_world = matrix_of_parent.copy()
|
||||||
coll.objects.link(root)
|
coll.objects.link(root)
|
||||||
root.hide_viewport = True
|
root.hide_viewport = True
|
||||||
hook['Root'] = root
|
hook['Root'] = root
|
||||||
@ -422,7 +431,7 @@ class TWEAKLAT_OT_Add_Objects(bpy.types.Operator):
|
|||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
class TWEAKLAT_OT_Remove_Objects(bpy.types.Operator):
|
class TWEAKLAT_OT_Remove_Selected_Objects(bpy.types.Operator):
|
||||||
"""Remove selected objects from this tweak lattice"""
|
"""Remove selected objects from this tweak lattice"""
|
||||||
bl_idname = "lattice.remove_selected_objects"
|
bl_idname = "lattice.remove_selected_objects"
|
||||||
bl_label = "Remove Selected Objects"
|
bl_label = "Remove Selected Objects"
|
||||||
@ -447,6 +456,22 @@ class TWEAKLAT_OT_Remove_Objects(bpy.types.Operator):
|
|||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class TWEAKLAT_OT_Remove_Object(bpy.types.Operator):
|
||||||
|
"""Remove this object from the tweak lattice"""
|
||||||
|
bl_idname = "lattice.remove_object"
|
||||||
|
bl_label = "Remove Object"
|
||||||
|
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
|
||||||
|
|
||||||
|
ob_pointer_prop_name: StringProperty(description="Name of the custom property that references the object that should be removed")
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
hook = context.object
|
||||||
|
target = hook[self.ob_pointer_prop_name]
|
||||||
|
|
||||||
|
# Add Lattice modifier to the selected objects
|
||||||
|
remove_objects_from_lattice(hook, [target])
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
class TWEAKLAT_PT_Main(bpy.types.Panel):
|
class TWEAKLAT_PT_Main(bpy.types.Panel):
|
||||||
bl_space_type = 'VIEW_3D'
|
bl_space_type = 'VIEW_3D'
|
||||||
@ -493,27 +518,36 @@ class TWEAKLAT_PT_Main(bpy.types.Panel):
|
|||||||
col.enabled = False
|
col.enabled = False
|
||||||
col.prop(root, 'parent')
|
col.prop(root, 'parent')
|
||||||
if root.parent and root.parent.type=='ARMATURE':
|
if root.parent and root.parent.type=='ARMATURE':
|
||||||
col.prop(root, 'parent_bone')
|
col.prop(root, 'parent_bone', icon='BONE_DATA')
|
||||||
|
|
||||||
layout.separator()
|
|
||||||
layout.label(text="Add Objects")
|
|
||||||
for o in context.selected_objects:
|
|
||||||
if o == hook or o.type!='MESH': continue
|
|
||||||
if o in hook.values(): continue
|
|
||||||
layout.label(text=o.name, icon='ADD')
|
|
||||||
layout.operator(TWEAKLAT_OT_Add_Objects.bl_idname, icon='ADD')
|
|
||||||
|
|
||||||
layout.separator()
|
|
||||||
layout.label(text="Remove Objects")
|
|
||||||
for o in context.selected_objects:
|
|
||||||
if o == hook or o.type!='MESH': continue
|
|
||||||
if o not in hook.values(): continue
|
|
||||||
layout.label(text=o.name, icon='REMOVE')
|
|
||||||
layout.operator(TWEAKLAT_OT_Remove_Objects.bl_idname, icon='REMOVE')
|
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.label(text="Affected Objects")
|
layout.label(text="Affected Objects")
|
||||||
|
|
||||||
|
num_to_add = 0
|
||||||
|
for o in context.selected_objects:
|
||||||
|
if o == hook or o.type!='MESH': continue
|
||||||
|
if o in hook.values(): continue
|
||||||
|
num_to_add += 1
|
||||||
|
if num_to_add == 1:
|
||||||
|
text = f"Add {o.name}"
|
||||||
|
if num_to_add:
|
||||||
|
if num_to_add > 1:
|
||||||
|
text = f"Add {num_to_add} Objects"
|
||||||
|
layout.operator(TWEAKLAT_OT_Add_Objects.bl_idname, icon='ADD', text=text)
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
num_to_remove = False
|
||||||
|
for o in context.selected_objects:
|
||||||
|
if o == hook or o.type!='MESH': continue
|
||||||
|
if o not in hook.values(): continue
|
||||||
|
num_to_remove += 1
|
||||||
|
if num_to_remove == 1:
|
||||||
|
text = f"Remove {o.name}"
|
||||||
|
if num_to_remove:
|
||||||
|
if num_to_remove > 1:
|
||||||
|
text = f"Remove {num_to_remove} Objects"
|
||||||
|
layout.operator(TWEAKLAT_OT_Remove_Selected_Objects.bl_idname, icon='REMOVE', text=text)
|
||||||
|
|
||||||
objects_and_keys = [(hook[key], key) for key in hook.keys() if "object_" in key]
|
objects_and_keys = [(hook[key], key) for key in hook.keys() if "object_" in key]
|
||||||
objects_and_keys.sort(key=lambda o_and_k: o_and_k[1])
|
objects_and_keys.sort(key=lambda o_and_k: o_and_k[1])
|
||||||
for ob, key in objects_and_keys:
|
for ob, key in objects_and_keys:
|
||||||
@ -521,6 +555,8 @@ class TWEAKLAT_PT_Main(bpy.types.Panel):
|
|||||||
row.prop(hook, f'["{key}"]', text="")
|
row.prop(hook, f'["{key}"]', text="")
|
||||||
mod = get_lattice_modifier_of_object(ob, hook['Lattice'])
|
mod = get_lattice_modifier_of_object(ob, hook['Lattice'])
|
||||||
row.prop_search(mod, 'vertex_group', ob, 'vertex_groups', text="", icon='GROUP_VERTEX')
|
row.prop_search(mod, 'vertex_group', ob, 'vertex_groups', text="", icon='GROUP_VERTEX')
|
||||||
|
op = row.operator(TWEAKLAT_OT_Remove_Object.bl_idname, text="", icon='X')
|
||||||
|
op.ob_pointer_prop_name = key
|
||||||
|
|
||||||
|
|
||||||
classes = [
|
classes = [
|
||||||
@ -528,7 +564,8 @@ classes = [
|
|||||||
,TWEAKLAT_OT_Delete
|
,TWEAKLAT_OT_Delete
|
||||||
,TWEAKLAT_OT_Falloff
|
,TWEAKLAT_OT_Falloff
|
||||||
,TWEAKLAT_OT_Add_Objects
|
,TWEAKLAT_OT_Add_Objects
|
||||||
,TWEAKLAT_OT_Remove_Objects
|
,TWEAKLAT_OT_Remove_Selected_Objects
|
||||||
|
,TWEAKLAT_OT_Remove_Object
|
||||||
,TWEAKLAT_PT_Main
|
,TWEAKLAT_PT_Main
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user