new addon simple_deform_helper #104464

Closed
EMM wants to merge 29 commits from Guai_Wo_Ge_EMM/blender-addons:simple_deform_helper into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 132 additions and 78 deletions
Showing only changes of commit 1a284b677b - Show all commits

View File

@ -122,15 +122,16 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
)
def draw_limits_line(self):
line_pos, limits_pos, = self.modifier_limits_point
up_point, down_point, up_limits, down_limits = self.modifier_limits_point
# draw limits line
self.draw_3d_shader(limits_pos, ((1, 0),), (1, 1, 0, 0.5))
self.draw_3d_shader((up_limits, down_limits), ((1, 0),), (1, 1, 0, 0.5))
# draw line
self.draw_3d_shader(line_pos, ((1, 0),), (1, 1, 0, 0.3))
self.draw_3d_shader((up_point, down_point), ((1, 0),), (1, 1, 0, 0.3))
# draw pos
self.draw_3d_shader([line_pos[1]], (), (0, 1, 0, 0.5),
self.draw_3d_shader([down_point], (), (0, 1, 0, 0.5),
shader_name='3D_UNIFORM_COLOR', draw_type='POINTS')
self.draw_3d_shader([line_pos[0]], (), (1, 0, 0, 0.5),
self.draw_3d_shader([up_point], (), (1, 0, 0, 0.5),
shader_name='3D_UNIFORM_COLOR', draw_type='POINTS')
def draw_deform_mesh(self):

View File

@ -55,7 +55,7 @@ class AngleUpdate(GizmoUtils):
elif not_c_l and not event.shift and is_shift and event.value == 'RELEASE':
self.init_mouse_region_x = event.mouse_region_x
new_value = self.tmp_value_angle = math.degrees(old_value)
# new_value = self.tmp_value_angle = math.degrees(old_value)
return
v(snap_value)
@ -113,7 +113,6 @@ class AngleGizmo(Gizmo, AngleUpdate):
self.update_prop_value(event, tweak)
self.update_header_text(context)
self.update_multiple_modifiers_data()
return self.event_handle(event)
def exit(self, context, cancel):

View File

@ -116,4 +116,4 @@ class BendAxiSwitchGizmoGroup(GizmoGroup, GizmoGroupUtils):
gizmo = getattr(self, i, False)
rot = Euler(w, 'XYZ').to_matrix().to_4x4()
gizmo.matrix_basis = mat.to_euler().to_matrix().to_4x4() @ rot
gizmo.matrix_basis.translation = Vector(j)
gizmo.matrix_basis.translation = self.obj_matrix_world @ Vector(j)

View File

@ -1,4 +1,5 @@
import math
from time import time
import bpy
from bpy.types import Gizmo, GizmoGroup
@ -200,6 +201,7 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
'down_limits', self.int_value_down_limits)
def modal(self, context, event, tweak):
st = time()
self.clear_cache()
if self.modifier_is_use_origin_axis:
@ -209,12 +211,12 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
self.middle_limits_value = (self.modifier_up_limits + self.modifier_down_limits) / 2
self.set_prop_value(event)
self.clear_data()
self.clear_cache()
self.update_multiple_modifiers_data()
self.update_object_origin_matrix()
# self.update_deform_wireframe(self.get_depsgraph(origin_object))
self.update_header_text(context)
return_handle = self.event_handle(event)
print('modal time sum ', time() - st)
return return_handle

View File

@ -1,42 +1,100 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from time import time
import bpy
from bpy.app.handlers import depsgraph_update_post, persistent
from .utils import GizmoUpdate
@persistent
def remove_not_use_empty(scene, dep):
"""Remove unused Empty Object
"""
remove_name: str = "ViewSimpleDeformGizmo_"
context = bpy.context
gizmo = GizmoUpdate()
gizmo.fix_origin_parent_and_angle()
# remove redundant empty object
class update_public:
_event_func_list = {}
update_func: 'function'
tmp_save_data = {}
run_time = 0.2
# simple update data if change active object on update
name = gizmo.obj.name
update_data = name not in gizmo.G_GizmoData or name != gizmo.G_GizmoData['active_object']
if update_data:
gizmo.clear_data()
gizmo.G_GizmoData[name] = name
gizmo.G_GizmoData['active_object'] = name
gizmo.G_Modifiers_TMP_Save_Data.clear()
if gizmo.simple_deform_modifier_is_simple(context):
for obj in context.scene.objects:
is_empty = obj.type == "EMPTY"
not_parent = not obj.parent
if remove_name in obj.name and not_parent and is_empty:
bpy.data.objects.remove(obj)
@classmethod
def register(cls):
import bpy
bpy.app.timers.register(cls.update_func, persistent=True)
@classmethod
def unregister(cls):
from bpy.app import timers
func = cls.update_func
if timers.is_registered(func):
timers.unregister(func)
@classmethod
def _update_call(cls):
for i in cls._event_func_list[cls]:
i()
@classmethod
def append(cls, item):
if cls not in cls._event_func_list:
cls._event_func_list[cls] = []
cls._event_func_list[cls].append(item)
@classmethod
def remove(cls, item):
if item in cls._event_func_list[cls]:
cls._event_func_list[cls].remove(item)
class change_active_object(update_public):
tmp_save_data = {}
from bpy.app.handlers import depsgraph_update_post, persistent
handler_type = depsgraph_update_post
@classmethod
def update_func(cls):
import bpy
name = bpy.context.object.name
key = 'active_object'
if key not in cls.tmp_save_data or cls.tmp_save_data[key] != name:
cls._update_call()
cls.tmp_save_data[key] = name
return cls.run_time
class change_active_simple_deform_modifier(update_public):
@classmethod
def update_func(cls):
import bpy
obj = bpy.context.object
if not obj or obj.type != 'MESH':
return cls.run_time
name = obj.name
key = 'active_object'
modifiers = cls.get_modifiers_data(obj)
change_modifiers = 'modifiers' not in cls.tmp_save_data or cls.tmp_save_data['modifiers'] != modifiers
if key not in cls.tmp_save_data or cls.tmp_save_data[key] != name:
cls.tmp_save_data['modifiers'] = modifiers
cls.tmp_save_data[key] = name
elif change_modifiers:
cls.tmp_save_data['modifiers'] = modifiers
cls._update_call()
return cls.run_time
@classmethod
def get_modifiers_data(cls, obj):
return {'obj': obj.name,
'active_modifier': getattr(obj.modifiers.active, 'name', None),
'modifiers': list(i.name for i in obj.modifiers)}
gizmo = GizmoUpdate()
def register():
depsgraph_update_post.append(remove_not_use_empty)
change_active_object.register()
change_active_simple_deform_modifier.register()
change_active_object.append(gizmo.update_multiple_modifiers_data)
change_active_simple_deform_modifier.append(gizmo.update_multiple_modifiers_data)
def unregister():
depsgraph_update_post.remove(remove_not_use_empty)
change_active_object.remove(gizmo.update_multiple_modifiers_data)
change_active_simple_deform_modifier.remove(gizmo.update_multiple_modifiers_data)
change_active_object.unregister()
change_active_simple_deform_modifier.unregister()

View File

@ -4,6 +4,7 @@ import math
import uuid
from functools import cache
from os.path import dirname, basename, realpath
from time import time
import bpy
import numpy as np
@ -17,7 +18,6 @@ class PublicData:
G_CustomShape = {}
G_GizmoData = {}
G_Modifiers_Data = {}
G_Modifiers_TMP_Save_Data = {}
G_INDICES = (
(0, 1), (0, 2), (1, 3), (2, 3),
(4, 5), (4, 6), (5, 7), (6, 7),
@ -315,12 +315,6 @@ class GizmoClassMethod(PublicUtils):
Vector((min_x, max_y, max_z))
)
@classmethod
def get_modifiers_data(cls, obj):
return {'obj': obj.name,
'active_modifier': obj.modifiers.active.name,
'modifiers': list(i.name for i in obj.modifiers)}
class PublicProperty(GizmoClassMethod):
@ -340,7 +334,7 @@ class PublicProperty(GizmoClassMethod):
g_l = self.__from_up_down_point_get_limits_point
if self.modifier.origin:
vector_axis = self.get_vector_axis(mod)
origin_mat = mod.origin.matrix_world.to_3x3()
origin_mat = mod.origin.matrix_basis.to_3x3()
axis_ = origin_mat @ vector_axis
point_lit = [[top, bottom], [left, right], [front, back]]
for f in range(point_lit.__len__()):
@ -378,17 +372,11 @@ class PublicProperty(GizmoClassMethod):
up_point, down_point = top, bottom
top, bottom = up_limits, down_limits = g_l(top, bottom)
(top, bottom, left,
right, front, back) = self.matrix_calculation(self.obj_matrix_world.inverted(),
(top, bottom, left, right, front, back))
points = ((up_point, down_point), (up_limits, down_limits))
points = (up_point, down_point, up_limits, down_limits)
each_point = ((right[0], back[1], top[2]), (left[0], front[1], bottom[2],))
box_bound_point = self.matrix_calculation(self.obj_matrix_world, self.tow_co_to_coordinate(each_point))
return points, box_bound_point
return points, self.tow_co_to_coordinate(each_point)
# ----------------------
@cache
def _each_face_pos(self, mat, co):
return self.co_to_direction(mat, co)
@ -401,13 +389,18 @@ class PublicProperty(GizmoClassMethod):
@classmethod
def clear_data(cls):
cls.G_GizmoData.clear()
@classmethod
def clear_modifiers_data(cls):
cls.G_Modifiers_Data.clear()
# --------------- Cache Data ----------------------
@property
def each_face_pos(self):
return self._each_face_pos(self.obj_matrix_world, self.get_bound_co_data())
matrix = Matrix()
matrix.freeze()
return self._each_face_pos(matrix, self.get_bound_co_data())
@property
def modifier_bound_co(self):
@ -415,17 +408,19 @@ class PublicProperty(GizmoClassMethod):
@property
def modifier_bound_box_pos(self):
return self._each_face_pos(self.obj_matrix_world, self.modifier_bound_co)
matrix = Matrix()
matrix.freeze()
return self.co_to_direction(matrix, self.modifier_bound_co)
@property
def modifier_limits_point(self):
points, _ = self._get_limits_point_and_bound_box_co()
return points
return self.matrix_calculation(self.obj_matrix_world, points)
@property
def modifier_limits_bound_box(self):
_, bound = self._get_limits_point_and_bound_box_co()
return bound
return self.matrix_calculation(self.obj_matrix_world, bound)
@property
def modifier_origin_angle_is_available(self):
@ -433,6 +428,7 @@ class PublicProperty(GizmoClassMethod):
self._get_limits_point_and_bound_box_co()
return True
except UnboundLocalError:
print('modifier_origin_angle_is_available')
self.clear_cache()
return False
@ -492,19 +488,19 @@ class PublicProperty(GizmoClassMethod):
# ----- point
@property
def point_up(self):
return self.modifier_limits_point[0][0]
return self.modifier_limits_point[0]
@property
def point_down(self):
return self.modifier_limits_point[0][1]
return self.modifier_limits_point[1]
@property
def point_limits_up(self):
return self.modifier_limits_point[1][0]
return self.modifier_limits_point[2]
@property
def point_limits_down(self):
return self.modifier_limits_point[1][1]
return self.modifier_limits_point[3]
# ------
@ -530,7 +526,7 @@ class PublicProperty(GizmoClassMethod):
@property
def modifier_is_use_origin_axis(self):
return self.obj_origin_property_group.origin_mode != 'NOT'
return self.obj_origin_property_group.origin_mode != 'NOT' and not self.modifier.origin
class GizmoUpdate(PublicProperty):
@ -598,6 +594,7 @@ class GizmoUpdate(PublicProperty):
return origin_object
def update_object_origin_matrix(self):
st = time()
origin_mode = self.origin_mode
origin_object = self.modifier.origin
is_use = self.modifier_is_use_origin_axis
@ -613,23 +610,21 @@ class GizmoUpdate(PublicProperty):
elif origin_mode == 'MIDDLE':
translation = (self.point_up + self.point_down) / 2
origin_object.matrix_world.translation = translation
print('update_object_origin_matrix', time() - st)
def update_multiple_modifiers_data(self):
print('update_multiple_modifiers_data', self)
st = time()
obj = self.obj
data = bpy.data
context = bpy.context
if obj.type not in ('MESH', 'LATTICE') or not self.simple_deform_public_poll(context):
return
self.clear_cache()
data = bpy.data
name = self.G_NAME
origin_object = data.objects.get(name)
modifiers = self.G_Modifiers_TMP_Save_Data
mods_data = self.get_modifiers_data(obj)
if 114514 in modifiers and modifiers[114514] == mods_data:
if origin_object:
self.update_deform_wireframe(self.get_depsgraph(origin_object))
return
# add simple_deform mesh
# update multiple simple_deform bound data
if origin_object:
data.objects.remove(origin_object)
@ -656,8 +651,7 @@ class GizmoUpdate(PublicProperty):
for mo in context.object.modifiers:
if mo.type == 'SIMPLE_DEFORM':
obj = self.get_depsgraph(deform_obj)
self.G_GizmoData[mo.name] = self.get_mesh_max_min_co(
obj)
self.G_Modifiers_Data[mo.name] = self.get_mesh_max_min_co(obj)
simple_deform = deform_obj.modifiers.new(
mo.name, 'SIMPLE_DEFORM')
simple_deform.deform_method = mo.deform_method
@ -676,7 +670,7 @@ class GizmoUpdate(PublicProperty):
deform_obj.hide_render = True
deform_obj.hide_viewport = True
deform_obj.hide_set(True)
self.G_Modifiers_TMP_Save_Data[114514] = mods_data
print('multiple_modifiers', time() - st)
def update_deform_wireframe(self, obj):
if not self.pref.update_deform_wireframe: