Add Lattice Magic to Addons #48

Merged
Nick Alberelli merged 36 commits from feature/lattice_magic into main 2023-05-17 20:48:52 +02:00
Showing only changes of commit 6405fd7b9b - Show all commits

View File

@ -25,7 +25,7 @@ from .utils import clamp, get_lattice_vertex_index, simple_driver
coll_name = 'Tweak Lattices' coll_name = 'Tweak Lattices'
def ensure_tweak_lattice_collection(scene): def ensure_tweak_lattice_collection(scene: bpy.types.Scene) -> bpy.types.Collection:
coll = bpy.data.collections.get(coll_name) coll = bpy.data.collections.get(coll_name)
if not coll: if not coll:
coll = bpy.data.collections.new(coll_name) coll = bpy.data.collections.new(coll_name)
@ -33,7 +33,9 @@ def ensure_tweak_lattice_collection(scene):
return coll return coll
def ensure_falloff_vgroup(lattice_ob: bpy.types.Object, vg_name="Group", multiplier=1, power=1) -> bpy.types.VertexGroup: def ensure_falloff_vgroup(
lattice_ob: bpy.types.Object,
vg_name="Group", multiplier=1, power=1) -> bpy.types.VertexGroup:
lattice = lattice_ob.data lattice = lattice_ob.data
res_x, res_y, res_z = lattice.points_u, lattice.points_v, lattice.points_w res_x, res_y, res_z = lattice.points_u, lattice.points_v, lattice.points_w
@ -62,6 +64,62 @@ def add_radius_constraint(obj, hook, target):
simple_driver(trans_con, prop, hook, '["Radius"]') simple_driver(trans_con, prop, hook, '["Radius"]')
return trans_con return trans_con
def get_objects_of_lattice(hook: bpy.types.Object) -> List[bpy.types.Object]:
objs = []
ob_count = 0
ob_prop_name = "object_"+str(ob_count)
while ob_prop_name in hook:
objs.append(hook[ob_prop_name])
return objs
def add_objects_to_lattice(
hook: bpy.types.Object,
objects: List[bpy.types.Object]):
lattice_ob = hook['Lattice']
# Check for existing
offset = 0
while "object_"+str(offset) in hook:
offset += 1
for i, o in enumerate(objects):
o.select_set(False)
if o.type!='MESH' or o in hook.values():
offset -= 1
continue
m = o.modifiers.new(name="Tweak Lattice", type='LATTICE')
m.object = lattice_ob
hook["object_"+str(i+offset)] = o
# Add driver to the modifier influence
simple_driver(m, 'strength', hook, '["Tweak Lattice"]')
def remove_all_objects_from_lattice(hook: bpy.types.Object) -> List[bpy.types.Object]:
lattice_ob = hook['Lattice']
objs = []
ob_count = 0
ob_prop_name = "object_"+str(ob_count)
while ob_prop_name in hook:
ob = hook[ob_prop_name]
for m in ob.modifiers:
if m.type!='LATTICE': continue
if m.object == lattice_ob:
m.driver_remove('strength')
ob.modifiers.remove(m)
break
ob_count += 1
objs.append(ob)
del hook[ob_prop_name]
ob_prop_name = "object_"+str(ob_count)
return objs
def remove_objects_from_lattice(hook, objects):
new_objs = []
prev_objs = remove_all_objects_from_lattice(hook)
for o in prev_objs:
if o not in objects:
new_objs.append(o)
add_objects_to_lattice(hook, new_objs)
class TWEAKLAT_OT_Create(bpy.types.Operator): class TWEAKLAT_OT_Create(bpy.types.Operator):
"""Create a lattice setup at the 3D cursor to deform selected objects""" """Create a lattice setup at the 3D cursor to deform selected objects"""
bl_idname = "lattice.create_tweak_lattice" bl_idname = "lattice.create_tweak_lattice"
@ -154,13 +212,7 @@ class TWEAKLAT_OT_Create(bpy.types.Operator):
hook_mod.vertex_group = vg.name hook_mod.vertex_group = vg.name
# Add Lattice modifier to the selected objects # Add Lattice modifier to the selected objects
for i, o in enumerate(context.selected_objects): add_objects_to_lattice(hook, context.selected_objects)
if o.type!='MESH': continue
m = o.modifiers.new(name="Tweak Lattice", type='LATTICE')
m.object = lattice_ob
hook["object_"+str(i)] = o
# Add driver to the modifier influence
simple_driver(m, 'strength', hook, '["Tweak Lattice"]')
# Set up Radius control. # Set up Radius control.
add_radius_constraint(hook, hook, root) add_radius_constraint(hook, hook, root)
@ -243,18 +295,7 @@ class TWEAKLAT_OT_Delete(bpy.types.Operator):
root = hook['Root'] root = hook['Root']
# Remove Lattice modifiers and their drivers. # Remove Lattice modifiers and their drivers.
ob_count = 0 remove_all_objects_from_lattice(hook)
ob_prop_name = "object_"+str(ob_count)
while ob_prop_name in hook:
ob = hook[ob_prop_name]
for m in ob.modifiers:
if m.type!='LATTICE': continue
if m.object == lattice:
m.driver_remove('strength')
ob.modifiers.remove(m)
break
ob_count += 1
ob_prop_name = "object_"+str(ob_count)
# Remove hook Action if exists. # Remove hook Action if exists.
if hook.animation_data and hook.animation_data.action: if hook.animation_data and hook.animation_data.action:
@ -275,6 +316,57 @@ class TWEAKLAT_OT_Delete(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class TWEAKLAT_OT_Add_Objects(bpy.types.Operator):
"""Add selected objects to this tweak lattice"""
bl_idname = "lattice.add_selected_objects"
bl_label = "Add Selected Objects"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
@classmethod
def poll(cls, context):
ob = context.object
if ob.type!='EMPTY' or 'Tweak Lattice' not in ob: return False
values = ob.values()
for sel_o in context.selected_objects:
if sel_o==ob or sel_o.type!='MESH': continue
if sel_o not in values:
return True
return False
def execute(self, context):
hook = context.object
# Add Lattice modifier to the selected objects
add_objects_to_lattice(hook, context.selected_objects)
return {'FINISHED'}
class TWEAKLAT_OT_Remove_Objects(bpy.types.Operator):
"""Remove selected objects from this tweak lattice"""
bl_idname = "lattice.remove_selected_objects"
bl_label = "Remove Selected Objects"
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
@classmethod
def poll(cls, context):
ob = context.object
if ob.type!='EMPTY' or 'Tweak Lattice' not in ob: return False
values = ob.values()
for sel_o in context.selected_objects:
if sel_o==ob or sel_o.type!='MESH': continue
if sel_o in values:
return True
return False
def execute(self, context):
hook = context.object
# Add Lattice modifier to the selected objects
remove_objects_from_lattice(hook, context.selected_objects)
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'
bl_region_type = 'UI' bl_region_type = 'UI'
@ -321,6 +413,22 @@ class TWEAKLAT_PT_Main(bpy.types.Panel):
root_row.prop(hook, '["Root"]', text="Root") root_row.prop(hook, '["Root"]', text="Root")
root_row.prop(hook['Root'], 'hide_viewport', text="", emboss=False) root_row.prop(hook['Root'], 'hide_viewport', text="", emboss=False)
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")
@ -335,6 +443,8 @@ classes = [
TWEAKLAT_OT_Create TWEAKLAT_OT_Create
,TWEAKLAT_OT_Delete ,TWEAKLAT_OT_Delete
,TWEAKLAT_OT_Falloff ,TWEAKLAT_OT_Falloff
,TWEAKLAT_OT_Add_Objects
,TWEAKLAT_OT_Remove_Objects
,TWEAKLAT_PT_Main ,TWEAKLAT_PT_Main
] ]