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.
4 changed files with 277 additions and 284 deletions
Showing only changes of commit 97c4bf3570 - Show all commits

View File

@ -105,7 +105,6 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
self.draw_scale_text(obj) self.draw_scale_text(obj)
if not self.modifier_origin_angle_is_available: if not self.modifier_origin_angle_is_available:
self.draw_bound_box() self.draw_bound_box()
...
if self.simple_deform_show_gizmo_poll(context): if self.simple_deform_show_gizmo_poll(context):
# draw bound box # draw bound box
self.draw_bound_box() self.draw_bound_box()
@ -136,6 +135,8 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
# draw pos # draw pos
self.draw_3d_shader([line_pos[1]], (), (0, 1, 0, 0.5), self.draw_3d_shader([line_pos[1]], (), (0, 1, 0, 0.5),
shader_name='3D_UNIFORM_COLOR', draw_type='POINTS') shader_name='3D_UNIFORM_COLOR', draw_type='POINTS')
self.draw_3d_shader([line_pos[0]], (), (1, 0, 0, 0.5),
shader_name='3D_UNIFORM_COLOR', draw_type='POINTS')
@classmethod @classmethod
def draw_deform_mesh(cls, ob, context): def draw_deform_mesh(cls, ob, context):
@ -151,8 +152,10 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
pos, indices, pref.deform_wireframe_color) pos, indices, pref.deform_wireframe_color)
def draw_scale_text(self, ob): def draw_scale_text(self, ob):
ob = self.obj scale_error = (ob.scale != Vector((1, 1, 1)))
dit = self.G_GizmoData if scale_error and ('handler_text' not in self.G_GizmoData):
if (ob.scale != Vector((1, 1, 1))) and ('handler_text' not in dit): self.G_GizmoData['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
dit['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
self.draw_str, (), 'WINDOW', 'POST_PIXEL') self.draw_str, (), 'WINDOW', 'POST_PIXEL')
def draw_origin_error(self):
...

View File

@ -1,5 +1,4 @@
import math import math
from typing import Callable, Any
import bpy import bpy
from bpy.types import Gizmo, GizmoGroup from bpy.types import Gizmo, GizmoGroup
@ -22,29 +21,13 @@ class GizmoProperty(GizmoUtils):
def is_down_limits_mode(self): def is_down_limits_mode(self):
return self.ctrl_mode == 'down_limits' return self.ctrl_mode == 'down_limits'
@property
def origin_mode(self):
return self.SimpleDeformGizmo_origin_property_group.origin_mode
@property
def is_middle_mode(self):
return self.origin_mode in ('LIMITS_MIDDLE', 'MIDDLE')
@property @property
def limit_scope(self): def limit_scope(self):
return self.pref.modifiers_limits_tolerance return self.pref.modifiers_limits_tolerance
@property
def difference_value(self):
return self.modifier_up_limits - self.modifier_down_limits
@property
def middle_value(self):
return (self.modifier_up_limits + self.modifier_down_limits) / 2
@property @property
def limits_min_value(self): def limits_min_value(self):
return self.modifier_up_limits + self.limit_scope return self.modifier_down_limits + self.limit_scope
@property @property
def limits_max_value(self): def limits_max_value(self):
@ -54,39 +37,22 @@ class GizmoProperty(GizmoUtils):
def get_up_limits_value(self, event): def get_up_limits_value(self, event):
delta = self.get_delta(event) delta = self.get_delta(event)
mid = self.middle_value + self.limit_scope mid = self.middle_limits_value + self.limit_scope
min_value = mid if self.is_middle_mode else self.limits_min_value min_value = mid if self.is_middle_mode else self.limits_min_value
return self.value_limit(delta, min_value=min_value) return self.value_limit(delta, min_value=min_value)
def get_down_limits_value(self, event): def get_down_limits_value(self, event):
delta = self.get_delta(event) delta = self.get_delta(event)
mid = self.middle_value - self.limit_scope mid = self.middle_limits_value - self.limit_scope
max_value = mid if self.is_middle_mode else self.limits_max_value max_value = mid if self.is_middle_mode else self.limits_max_value
return self.value_limit(delta, max_value=max_value) return self.value_limit(delta, max_value=max_value)
def get_delta(self, event):
class GizmoUpdate(GizmoProperty): context = bpy.context
def update_gizmo_matrix(self, context):
self.align_orientation_to_user_perspective(context)
self.align_point_to_limits_point()
def align_orientation_to_user_perspective(self, context):
rotation = context.space_data.region_3d.view_matrix.inverted().to_quaternion()
matrix = rotation.to_matrix().to_4x4()
self.matrix_basis = matrix
def align_point_to_limits_point(self):
if self.is_up_limits_mode:
self.matrix_basis.translation = self.point_limits_up
elif self.is_down_limits_mode:
self.matrix_basis.translation = self.point_limits_down
def delta_update(self, context, event, delta):
x, y = view3d_utils.location_3d_to_region_2d( x, y = view3d_utils.location_3d_to_region_2d(
context.region, context.space_data.region_3d, self.up) context.region, context.space_data.region_3d, self.point_up)
x2, y2 = view3d_utils.location_3d_to_region_2d( x2, y2 = view3d_utils.location_3d_to_region_2d(
context.region, context.space_data.region_3d, self.down) context.region, context.space_data.region_3d, self.point_down)
mouse_line_distance = math.sqrt(((event.mouse_region_x - x2) ** 2) + mouse_line_distance = math.sqrt(((event.mouse_region_x - x2) ** 2) +
((event.mouse_region_y - y2) ** 2)) ((event.mouse_region_y - y2) ** 2))
@ -104,20 +70,43 @@ class GizmoUpdate(GizmoProperty):
angle_ = mouse_angle.angle(limits_angle) angle_ = mouse_angle.angle(limits_angle)
if angle_ > (math.pi / 2): if angle_ > (math.pi / 2):
delta = 0 delta = 0
return delta return delta
class GizmoUpdate(GizmoProperty):
# ---update gizmo matrix
def update_gizmo_matrix(self, context):
self.align_orientation_to_user_perspective(context)
self.align_point_to_limits_point()
def align_orientation_to_user_perspective(self, context):
rotation = context.space_data.region_3d.view_matrix.inverted().to_quaternion()
matrix = rotation.to_matrix().to_4x4()
self.matrix_basis = matrix
def align_point_to_limits_point(self):
if self.is_up_limits_mode:
self.matrix_basis.translation = self.point_limits_up
elif self.is_down_limits_mode:
self.matrix_basis.translation = self.point_limits_down
# ---- set prop
def set_prop_value(self, event):
if self.is_up_limits_mode:
self.set_up_value(event)
elif self.is_down_limits_mode:
self.set_down_value(event)
def set_down_value(self, event): def set_down_value(self, event):
value = self.get_down_limits_value(event) value = self.get_down_limits_value(event)
self.target_set_value('down_limits', value) self.target_set_value('down_limits', value)
if event.ctrl: if event.ctrl:
self.target_set_value( self.target_set_value('up_limits', value + self.difference_value)
'up_limits', value + self.difference_value)
elif self.is_middle_mode: elif self.is_middle_mode:
if self.origin_mode == 'LIMITS_MIDDLE': if self.origin_mode == 'LIMITS_MIDDLE':
mu = self.middle_value mu = self.middle_limits_value
self.target_set_value('up_limits', mu - (value - mu)) v = mu - (value - mu)
self.target_set_value('up_limits', v)
elif self.origin_mode == 'MIDDLE': elif self.origin_mode == 'MIDDLE':
self.target_set_value('up_limits', 1 - value) self.target_set_value('up_limits', 1 - value)
else: else:
@ -129,12 +118,12 @@ class GizmoUpdate(GizmoProperty):
value = self.get_up_limits_value(event) value = self.get_up_limits_value(event)
self.target_set_value('up_limits', value) self.target_set_value('up_limits', value)
if event.ctrl: if event.ctrl:
self.target_set_value( self.target_set_value('down_limits', value - self.difference_value)
'down_limits', value - self.difference_value)
elif self.is_middle_mode: elif self.is_middle_mode:
if self.origin_mode == 'LIMITS_MIDDLE': if self.origin_mode == 'LIMITS_MIDDLE':
mu = self.middle_value mu = self.middle_limits_value
self.target_set_value('down_limits', mu - (value - mu)) value = mu - (value - mu)
self.target_set_value('down_limits', value)
elif self.origin_mode == 'MIDDLE': elif self.origin_mode == 'MIDDLE':
self.target_set_value('down_limits', 1 - value) self.target_set_value('down_limits', 1 - value)
else: else:
@ -142,14 +131,9 @@ class GizmoUpdate(GizmoProperty):
else: else:
self.target_set_value('down_limits', self.modifier_down_limits) self.target_set_value('down_limits', self.modifier_down_limits)
def set_prop_value(self, event): # -------
if self.is_up_limits_mode:
self.set_up_value(event)
elif self.is_down_limits_mode:
self.set_down_value(event)
def update_header_text(self, context): def update_header_text(self, context):
origin = self.SimpleDeformGizmo_origin_property_group origin = self.obj_origin_property_group
mode = origin.bl_rna.properties['origin_mode'].enum_items[origin.origin_mode].name mode = origin.bl_rna.properties['origin_mode'].enum_items[origin.origin_mode].name
t = self.translate_header_text t = self.translate_header_text
@ -157,30 +141,35 @@ class GizmoUpdate(GizmoProperty):
if self.is_up_limits_mode: if self.is_up_limits_mode:
value = round(self.modifier_up_limits, 3) value = round(self.modifier_up_limits, 3)
text += t('Upper limit', value) text += t('Up limit', value)
elif self.is_down_limits_mode: elif self.is_down_limits_mode:
value = round(self.modifier_down_limits, 3) value = round(self.modifier_down_limits, 3)
text += t('Down limit', value) text += t('Down limit', value)
context.area.header_text_set(text) context.area.header_text_set(text)
def event_ops(self, event, ob, origin): # def update_modifiers_origin_matrix(self):
"""通过输入键位来更改属性""" # ob = bpy.context.object
# event ctrl # for mod in ob.modifiers:
data_path = ('object.SimpleDeformGizmo_PropertyGroup.origin_mode', # if mod.type == 'SIMPLE_DEFORM':
'object.modifiers.active.origin.SimpleDeformGizmo_PropertyGroup.origin_mode') # self.update_matrix(mod, ob)
#
if event.type in ('WHEELUPMOUSE', 'WHEELDOWNMOUSE'): # def update_matrix(self, mod, ob):
reverse = (event.type == 'WHEELUPMOUSE') # # if mod.deform_method == 'BEND':
for path in data_path: # # cls.new_empty(ob, mod)
bpy.ops.wm.context_cycle_enum( # origin_object = mod.origin
data_path=path, reverse=reverse, wrap=True) # if mod.origin:
elif event.type in ('X', 'Y', 'Z'): # modifiers_co = self.G_GizmoData['modifiers_co']
ob.modifiers.active.deform_axis = event.type # for index, mod_name in enumerate(modifiers_co):
elif event.type == 'A': # co_items = list(modifiers_co.items())
self.pref.display_bend_axis_switch_gizmo = True # if mod.name == mod_name:
return {'FINISHED'} # data = co_items[index - 1][1] if (
# index or (index != 1)) else modifiers_co['co']
return {'RUNNING_MODAL'} # (up, down), (up_, down_) = self.get_limits_pos(
# mod, self.co_to_direction(ob.matrix_world.copy(), data))
# origin_mode = self.obj_origin_property_group(
# mod, ob).origin_mode
# self.set_empty_obj_matrix(
# origin_mode, origin_object, up_, down_, up, down)
class UpDownLimitsGizmo(Gizmo, GizmoUpdate): class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
@ -190,6 +179,7 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
{'id': 'up_limits', 'type': 'FLOAT', 'array_length': 1}, {'id': 'up_limits', 'type': 'FLOAT', 'array_length': 1},
{'id': 'down_limits', 'type': 'FLOAT', 'array_length': 1}, {'id': 'down_limits', 'type': 'FLOAT', 'array_length': 1},
) )
bl_options = {'UNDO', 'GRAB_CURSOR'}
__slots__ = ( __slots__ = (
'mod', 'mod',
@ -198,12 +188,16 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
'draw_type', 'draw_type',
'mouse_dpi', 'mouse_dpi',
'ctrl_mode', 'ctrl_mode',
'difference_value',
'middle_limits_value',
'init_mouse_region_y', 'init_mouse_region_y',
'init_mouse_region_x', 'init_mouse_region_x',
'custom_shape', 'custom_shape',
'int_value_up_limits', 'int_value_up_limits',
'int_value_down_limits', 'int_value_down_limits',
) )
difference_value: float
middle_limits_value: float
def setup(self): def setup(self):
self.mouse_dpi = 10 self.mouse_dpi = 10
@ -232,15 +226,17 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
def modal(self, context, event, tweak): def modal(self, context, event, tweak):
self.clear_cache() self.clear_cache()
if self.modifier_is_use_origin_axis:
self.new_origin_empty_object()
self.difference_value = self.modifier_up_limits - self.modifier_down_limits
self.middle_limits_value = (self.modifier_up_limits + self.modifier_down_limits) / 2
self.set_prop_value(event) self.set_prop_value(event)
if self.SimpleDeformGizmo_is_use_empty_as_axis: self.update_object_origin_matrix()
self.new_empty(self.obj, self.modifier)
# self.update_empty_matrix()
# self.update_header_text(context, mod, origin, up_limits, down_limits) self.update_header_text(context)
return self.event_handle(event)
# return self.event_ops(event, ob, origin)
return {'RUNNING_MODAL'}
class UpDownLimitsGizmoGroup(GizmoGroup, GizmoGroupUtils): class UpDownLimitsGizmoGroup(GizmoGroup, GizmoGroupUtils):
@ -286,15 +282,3 @@ class UpDownLimitsGizmoGroup(GizmoGroup, GizmoGroupUtils):
for i in (self.down_limits, self.up_limits): for i in (self.down_limits, self.up_limits):
for j in ('down_limits', 'up_limits'): for j in ('down_limits', 'up_limits'):
i.target_set_prop(j, pro, j) i.target_set_prop(j, pro, j)
self.down_limits.target_set_prop('down_limits',
pro,
'down_limits')
self.down_limits.target_set_prop('up_limits',
pro,
'up_limits')
self.up_limits.target_set_prop('down_limits',
pro,
'down_limits')
self.up_limits.target_set_prop('up_limits',
pro,
'up_limits')

View File

@ -30,7 +30,7 @@ class DeformAxisOperator(Operator, GizmoUtils):
mod = context.object.modifiers.active mod = context.object.modifiers.active
mod.deform_axis = self.Deform_Axis mod.deform_axis = self.Deform_Axis
empty, con_limit_name = GizmoUtils.new_empty(context.object, mod) empty, con_limit_name = GizmoUtils.new_origin_empty_object(context.object, mod)
is_positive = GizmoUtils.is_positive(mod.angle) is_positive = GizmoUtils.is_positive(mod.angle)
for limit, value in (('max_x', self.X_Value), for limit, value in (('max_x', self.X_Value),

View File

@ -278,65 +278,6 @@ class PublicUtils(PublicPoll):
class GizmoClassMethod(PublicUtils): class GizmoClassMethod(PublicUtils):
@classmethod
def new_empty(cls, obj, mod):
origin = mod.origin
if origin is None:
new_name = cls.G_NAME + '_Empty_' + str(uuid.uuid4())
origin_object = bpy.data.objects.new(new_name, None)
cls.link_obj_to_active_collection(origin_object)
origin_object.hide_set(True)
origin_object.empty_display_size = min(obj.dimensions)
mod.origin = origin_object
else:
origin_object = mod.origin
origin_object.hide_viewport = False
if origin_object.parent != obj:
origin_object.parent = obj
# add constraints
con_name = cls.G_CON_LIMIT_NAME
if con_name in origin_object.constraints.keys():
limit_constraints = origin.constraints.get(con_name)
else:
limit_constraints = origin_object.constraints.new(
'LIMIT_ROTATION')
limit_constraints.name = con_name
limit_constraints.owner_space = 'WORLD'
limit_constraints.space_object = obj
limit_constraints.use_transform_limit = True
limit_constraints.use_limit_x = True
limit_constraints.use_limit_y = True
limit_constraints.use_limit_z = True
con_copy_name = cls.G_NAME + 'constraints_copy_rotation'
if con_copy_name in origin_object.constraints.keys():
copy_constraints = origin.constraints.get(con_copy_name)
else:
copy_constraints = origin_object.constraints.new(
'COPY_ROTATION')
copy_constraints.name = con_copy_name
copy_constraints.target = obj
copy_constraints.mix_mode = 'BEFORE'
copy_constraints.target_space = 'WORLD'
copy_constraints.owner_space = 'WORLD'
origin_object.rotation_euler.zero()
origin_object.scale = 1, 1, 1
return origin_object, con_name
@classmethod
def set_empty_obj_matrix(cls, origin_mode, empty_object, up_, down_, up, down):
tow = Vector((2, 2, 2))
if origin_mode == 'UP_LIMITS':
empty_object.matrix_world.translation = Vector(up_)
elif origin_mode == 'DOWN_LIMITS':
empty_object.matrix_world.translation = Vector(
down_)
elif origin_mode == 'LIMITS_MIDDLE':
empty_object.matrix_world.translation = (up_ + down_) / tow
elif origin_mode == 'MIDDLE':
empty_object.matrix_world.translation = (up + down) / tow
@classmethod @classmethod
def get_vector_axis(cls, mod): def get_vector_axis(cls, mod):
axis = mod.deform_axis axis = mod.deform_axis
@ -550,7 +491,7 @@ class PublicProperty(GizmoClassMethod):
# ------ # ------
@property @property
def SimpleDeformGizmo_origin_property_group(self): def obj_origin_property_group(self):
mod = self.modifier mod = self.modifier
if mod.origin: if mod.origin:
return mod.origin.SimpleDeformGizmo_PropertyGroup return mod.origin.SimpleDeformGizmo_PropertyGroup
@ -558,132 +499,179 @@ class PublicProperty(GizmoClassMethod):
return self.obj.SimpleDeformGizmo_PropertyGroup return self.obj.SimpleDeformGizmo_PropertyGroup
@property @property
def SimpleDeformGizmo_is_use_empty_as_axis(self): def origin_mode(self):
return self.SimpleDeformGizmo_origin_property_group.origin_mode != 'NOT' return self.obj_origin_property_group.origin_mode
@property
def is_limits_middle_mode(self):
return self.origin_mode == 'LIMITS_MIDDLE'
@property
def is_middle_mode(self):
return self.origin_mode in ('LIMITS_MIDDLE', 'MIDDLE')
@property
def modifier_is_use_origin_axis(self):
return self.obj_origin_property_group.origin_mode != 'NOT'
class GizmoUpdate(PublicProperty): class GizmoUpdate(PublicProperty):
@classmethod def new_origin_empty_object(self):
def update_matrix(cls, mod, ob): mod = self.modifier
if mod.deform_method == 'BEND': obj = self.obj
cls.new_empty(ob, mod) origin = mod.origin
if mod.origin: if not origin:
empty_object = mod.origin new_name = self.G_NAME + '_Empty_' + str(uuid.uuid4())
modifiers_co = cls.G_GizmoData['modifiers_co'] origin_object = bpy.data.objects.new(new_name, None)
for index, mod_name in enumerate(modifiers_co): self.link_obj_to_active_collection(origin_object)
co_items = list(modifiers_co.items()) origin_object.hide_set(True)
if mod.name == mod_name: origin_object.empty_display_size = min(obj.dimensions)
data = co_items[index - 1][1] if ( mod.origin = origin_object
index or (index != 1)) else modifiers_co['co'] else:
(up, down), (up_, down_) = cls.get_limits_pos( origin_object = mod.origin
mod, cls.co_to_direction(ob.matrix_world.copy(), data)) origin_object.hide_viewport = False
origin_mode = cls.SimpleDeformGizmo_origin_property_group(
mod, ob).origin_mode
cls.set_empty_obj_matrix(
origin_mode, empty_object, up_, down_, up, down)
# @classmethod if origin_object.parent != obj:
# def update_empty_matrix(cls): origin_object.parent = obj
# ob = bpy.context.object
# for mod in ob.modifiers: # add constraints
# if mod.type == 'SIMPLE_DEFORM': name = self.G_CON_LIMIT_NAME
# cls.update_matrix(mod, ob) if origin_object.constraints.keys().__len__() > 1:
# origin_object.constraints.clear()
# @classmethod if name in origin_object.constraints.keys():
# context = bpy.context limit_constraints = origin.constraints.get(name)
# data = bpy.data else:
# matrix = obj.matrix_world.copy() # 物体矩阵 limit_constraints = origin_object.constraints.new(
# # add simple_deform mesh 'LIMIT_ROTATION')
# (min_x, min_y, min_z), (max_x, max_y, limit_constraints.name = name
# max_z) = cls.get_mesh_max_min_co(obj) limit_constraints.owner_space = 'WORLD'
# vertexes = ((max_x, min_y, min_z), limit_constraints.space_object = obj
# (min_x, min_y, min_z), limit_constraints.use_transform_limit = True
# (max_x, max_y, min_z), limit_constraints.use_limit_x = True
# (min_x, max_y, min_z), limit_constraints.use_limit_y = True
# (max_x, min_y, max_z), limit_constraints.use_limit_z = True
# (min_x, min_y, max_z), con_copy_name = self.G_NAME + 'constraints_copy_rotation'
# (max_x, max_y, max_z), if con_copy_name in origin_object.constraints.keys():
# (min_x, max_y, max_z)) copy_constraints = origin.constraints.get(con_copy_name)
# name = cls.G_NAME else:
# if data.objects.get(name): copy_constraints = origin_object.constraints.new(
# data.objects.remove(data.objects.get(name)) 'COPY_ROTATION')
# copy_constraints.name = con_copy_name
# if data.meshes.get(name): copy_constraints.target = obj
# data.meshes.remove(data.meshes.get(name)) copy_constraints.mix_mode = 'BEFORE'
# mesh = data.meshes.new(name) copy_constraints.target_space = 'WORLD'
# mesh.from_pydata(vertexes, cls.G_INDICES, []) copy_constraints.owner_space = 'WORLD'
# mesh.update() origin_object.rotation_euler.zero()
# origin_object.scale = 1, 1, 1
# new_object = data.objects.new(name, mesh)
# def update_object_origin_matrix(self):
# cls.link_obj_to_active_collection(new_object) self.clear_data()
# origin_mode = self.origin_mode
# if new_object.parent != obj: empty_object = self.modifier.origin
# new_object.parent = obj if empty_object and self.modifier_is_use_origin_axis :
# if origin_mode == 'UP_LIMITS':
# new_object.modifiers.clear() empty_object.matrix_world.translation = Vector(self.point_limits_up)
# subdivision = new_object.modifiers.new('1', 'SUBSURF') elif origin_mode == 'DOWN_LIMITS':
# subdivision.levels = 7 empty_object.matrix_world.translation = Vector(self.point_limits_down)
# cls.G_GizmoData['modifiers_co'] = {} elif origin_mode == 'LIMITS_MIDDLE':
# cls.G_GizmoData['modifiers_co']['co'] = ( translation = (self.point_limits_up + self.point_limits_down) / 2
# min_x, min_y, min_z), (max_x, max_y, max_z) empty_object.matrix_world.translation = translation
# for mo in context.object.modifiers: elif origin_mode == 'MIDDLE':
# if mo.type == 'SIMPLE_DEFORM': translation = (self.point_up + self.point_down) / 2
# simple_deform = new_object.modifiers.new( empty_object.matrix_world.translation = translation
# mo.name, 'SIMPLE_DEFORM')
# simple_deform.deform_method = mo.deform_method
# simple_deform.deform_axis = mo.deform_axis
# simple_deform.lock_x = mo.lock_x
# simple_deform.lock_y = mo.lock_y
# simple_deform.lock_z = mo.lock_z
# simple_deform.origin = mo.origin
# simple_deform.limits[1] = mo.limits[1]
# simple_deform.limits[0] = mo.limits[0]
# simple_deform.angle = mo.angle
# simple_deform.show_viewport = mo.show_viewport
# obj = PublicUtils.get_depsgraph(new_object)
# cls.G_GizmoData['modifiers_co'][mo.name] = cls.get_mesh_max_min_co(
# obj)
# new_object.hide_set(True)
# new_object.hide_viewport = False
# new_object.hide_select = True
# new_object.hide_render = True
# new_object.hide_viewport = True
# new_object.hide_set(True)
# ver_len = obj.data.vertices.__len__()
# edge_len = obj.data.edges.__len__()
#
# if 'numpy_data' not in cls.G_GizmoData:
# cls.G_GizmoData['numpy_data'] = {}
#
# numpy_data = cls.G_GizmoData['numpy_data']
# key = (ver_len, edge_len)
# if key in numpy_data:
# list_edges, list_vertices = numpy_data[key]
# else:
# list_edges = np.zeros(edge_len * 2, dtype=np.int32)
# list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
# numpy_data[key] = (list_edges, list_vertices)
# obj.data.vertices.foreach_get('co', list_vertices)
# ver = list_vertices.reshape((ver_len, 3))
# ver = np.insert(ver, 3, 1, axis=1).T
# ver[:] = np.dot(matrix, ver)
#
# ver /= ver[3, :]
# ver = ver.T
# ver = ver[:, :3]
# obj.data.edges.foreach_get('vertices', list_edges)
# indices = list_edges.reshape((edge_len, 2))
#
# limits = context.object.modifiers.active.limits[:]
# modifiers = [getattr(context.object.modifiers.active, i)
# for i in cls.G_MODIFIERS_PROPERTY]
#
# cls.G_GizmoData['draw'] = (ver, indices, matrix, modifiers, limits)
def update_deform_wireframe(self): def update_deform_wireframe(self):
... context = bpy.context
data = bpy.data
matrix = obj.matrix_world.copy() # 物体矩阵
# add simple_deform mesh
(min_x, min_y, min_z), (max_x, max_y,
max_z) = cls.get_mesh_max_min_co(obj)
vertexes = ((max_x, min_y, min_z),
(min_x, min_y, min_z),
(max_x, max_y, min_z),
(min_x, max_y, min_z),
(max_x, min_y, max_z),
(min_x, min_y, max_z),
(max_x, max_y, max_z),
(min_x, max_y, max_z))
name = cls.G_NAME
if data.objects.get(name):
data.objects.remove(data.objects.get(name))
if data.meshes.get(name):
data.meshes.remove(data.meshes.get(name))
mesh = data.meshes.new(name)
mesh.from_pydata(vertexes, cls.G_INDICES, [])
mesh.update()
new_object = data.objects.new(name, mesh)
cls.link_obj_to_active_collection(new_object)
if new_object.parent != obj:
new_object.parent = obj
new_object.modifiers.clear()
subdivision = new_object.modifiers.new('1', 'SUBSURF')
subdivision.levels = 7
cls.G_GizmoData['modifiers_co'] = {}
cls.G_GizmoData['modifiers_co']['co'] = (
min_x, min_y, min_z), (max_x, max_y, max_z)
for mo in context.object.modifiers:
if mo.type == 'SIMPLE_DEFORM':
simple_deform = new_object.modifiers.new(
mo.name, 'SIMPLE_DEFORM')
simple_deform.deform_method = mo.deform_method
simple_deform.deform_axis = mo.deform_axis
simple_deform.lock_x = mo.lock_x
simple_deform.lock_y = mo.lock_y
simple_deform.lock_z = mo.lock_z
simple_deform.origin = mo.origin
simple_deform.limits[1] = mo.limits[1]
simple_deform.limits[0] = mo.limits[0]
simple_deform.angle = mo.angle
simple_deform.show_viewport = mo.show_viewport
obj = PublicUtils.get_depsgraph(new_object)
cls.G_GizmoData['modifiers_co'][mo.name] = cls.get_mesh_max_min_co(
obj)
new_object.hide_set(True)
new_object.hide_viewport = False
new_object.hide_select = True
new_object.hide_render = True
new_object.hide_viewport = True
new_object.hide_set(True)
ver_len = obj.data.vertices.__len__()
edge_len = obj.data.edges.__len__()
if 'numpy_data' not in cls.G_GizmoData:
cls.G_GizmoData['numpy_data'] = {}
numpy_data = cls.G_GizmoData['numpy_data']
key = (ver_len, edge_len)
if key in numpy_data:
list_edges, list_vertices = numpy_data[key]
else:
list_edges = np.zeros(edge_len * 2, dtype=np.int32)
list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
numpy_data[key] = (list_edges, list_vertices)
obj.data.vertices.foreach_get('co', list_vertices)
ver = list_vertices.reshape((ver_len, 3))
ver = np.insert(ver, 3, 1, axis=1).T
ver[:] = np.dot(matrix, ver)
ver /= ver[3, :]
ver = ver.T
ver = ver[:, :3]
obj.data.edges.foreach_get('vertices', list_edges)
indices = list_edges.reshape((edge_len, 2))
limits = context.object.modifiers.active.limits[:]
modifiers = [getattr(context.object.modifiers.active, i)
for i in cls.G_MODIFIERS_PROPERTY]
cls.G_GizmoData['draw'] = (ver, indices, matrix, modifiers, limits)
class GizmoUtils(GizmoUpdate): class GizmoUtils(GizmoUpdate):
@ -725,7 +713,7 @@ class GizmoUtils(GizmoUpdate):
self.init_mouse_region_y = event.mouse_region_y self.init_mouse_region_y = event.mouse_region_y
self.init_mouse_region_x = event.mouse_region_x self.init_mouse_region_x = event.mouse_region_x
def _update_matrix(self, context): def __update_matrix_func(self, context):
func = getattr(self, 'update_gizmo_matrix', None) func = getattr(self, 'update_gizmo_matrix', None)
if func and self.modifier_origin_angle_is_available: if func and self.modifier_origin_angle_is_available:
func(context) func(context)
@ -733,13 +721,13 @@ class GizmoUtils(GizmoUpdate):
def draw(self, context): def draw(self, context):
if self.modifier_origin_angle_is_available: if self.modifier_origin_angle_is_available:
self.draw_custom_shape(self.custom_shape[self.draw_type]) self.draw_custom_shape(self.custom_shape[self.draw_type])
self._update_matrix(context) self.__update_matrix_func(context)
def draw_select(self, context, select_id): def draw_select(self, context, select_id):
if self.modifier_origin_angle_is_available: if self.modifier_origin_angle_is_available:
self.draw_custom_shape( self.draw_custom_shape(
self.custom_shape[self.draw_type], select_id=select_id) self.custom_shape[self.draw_type], select_id=select_id)
self._update_matrix(context) self.__update_matrix_func(context)
def get_delta(self, event): def get_delta(self, event):
delta = (self.init_mouse_region_x - event.mouse_region_x) / self.mouse_dpi delta = (self.init_mouse_region_x - event.mouse_region_x) / self.mouse_dpi
@ -764,6 +752,24 @@ class GizmoUtils(GizmoUpdate):
def update_gizmo_matrix(self): def update_gizmo_matrix(self):
... ...
def event_handle(self, event):
"""通过输入键位来更改属性"""
# event ctrl
data_path = ('object.SimpleDeformGizmo_PropertyGroup.origin_mode',
'object.modifiers.active.origin.SimpleDeformGizmo_PropertyGroup.origin_mode')
if event.type in ('WHEELUPMOUSE', 'WHEELDOWNMOUSE'):
reverse = (event.type == 'WHEELUPMOUSE')
for path in data_path:
bpy.ops.wm.context_cycle_enum(
data_path=path, reverse=reverse, wrap=True)
elif event.type in ('X', 'Y', 'Z'):
self.obj.modifiers.active.deform_axis = event.type
elif event.type == 'A':
self.pref.display_bend_axis_switch_gizmo = True
return {'FINISHED'}
return {'RUNNING_MODAL'}
class GizmoGroupUtils(GizmoUtils): class GizmoGroupUtils(GizmoUtils):
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'