new addon simple_deform_helper #104464
@ -11,16 +11,16 @@ from .utils import GizmoUtils
|
|||||||
class Handler:
|
class Handler:
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_handler(cls):
|
def add_handler(cls):
|
||||||
if 'handler' not in cls.G_SimpleDeformGizmoHandlerDit:
|
if 'handler' not in cls.G_GizmoData:
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['handler'] = bpy.types.SpaceView3D.draw_handler_add(
|
cls.G_GizmoData['handler'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||||
Draw3D.draw_bound_box, (), 'WINDOW', 'POST_VIEW')
|
Draw3D().draw, (), 'WINDOW', 'POST_VIEW')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def del_handler_text(cls):
|
def del_handler_text(cls):
|
||||||
if 'handler_text' in cls.G_SimpleDeformGizmoHandlerDit:
|
if 'handler_text' in cls.G_GizmoData:
|
||||||
bpy.types.SpaceView3D.draw_handler_remove(
|
bpy.types.SpaceView3D.draw_handler_remove(
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['handler_text'], 'WINDOW')
|
cls.G_GizmoData['handler_text'], 'WINDOW')
|
||||||
cls.G_SimpleDeformGizmoHandlerDit.pop('handler_text')
|
cls.G_GizmoData.pop('handler_text')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def del_handler(cls):
|
def del_handler(cls):
|
||||||
@ -33,54 +33,13 @@ class Handler:
|
|||||||
|
|
||||||
cls.del_handler_text()
|
cls.del_handler_text()
|
||||||
|
|
||||||
if 'handler' in cls.G_SimpleDeformGizmoHandlerDit:
|
if 'handler' in cls.G_GizmoData:
|
||||||
bpy.types.SpaceView3D.draw_handler_remove(
|
bpy.types.SpaceView3D.draw_handler_remove(
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['handler'], 'WINDOW')
|
cls.G_GizmoData['handler'], 'WINDOW')
|
||||||
cls.G_SimpleDeformGizmoHandlerDit.clear()
|
cls.G_GizmoData.clear()
|
||||||
|
|
||||||
|
|
||||||
class Draw3D(GizmoUtils):
|
class DrawPublic:
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def draw_bound_box(cls):
|
|
||||||
gpu.state.blend_set('ALPHA')
|
|
||||||
gpu.state.line_width_set(1)
|
|
||||||
|
|
||||||
gpu.state.blend_set('ALPHA')
|
|
||||||
gpu.state.depth_test_set('ALWAYS')
|
|
||||||
|
|
||||||
context = bpy.context
|
|
||||||
if cls.simple_deform_public_poll(context):
|
|
||||||
cls.is_draw_box(context)
|
|
||||||
else:
|
|
||||||
Handler.del_handler()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def is_draw_box(cls, context):
|
|
||||||
obj = context.object # 活动物体
|
|
||||||
matrix = obj.matrix_world # 活动物体矩阵
|
|
||||||
modifier = context.object.modifiers.active # 活动修改器
|
|
||||||
|
|
||||||
pref = cls.pref_()
|
|
||||||
simple_poll = cls.simple_deform_public_poll(context)
|
|
||||||
bend = modifier and (modifier.deform_method == 'BEND')
|
|
||||||
display_switch_axis = not pref.display_bend_axis_switch_gizmo
|
|
||||||
|
|
||||||
cls.draw_scale_text(obj)
|
|
||||||
cls.update_co_data(obj, modifier)
|
|
||||||
|
|
||||||
co_data = cls.generate_co_data()
|
|
||||||
|
|
||||||
if simple_poll and ((not bend) or display_switch_axis):
|
|
||||||
# draw bound box
|
|
||||||
cls.draw_box(co_data, matrix)
|
|
||||||
# cls.draw_deform_mesh(obj, context)
|
|
||||||
cls.draw_limits_line()
|
|
||||||
cls.draw_limits_bound_box()
|
|
||||||
elif simple_poll and (bend and not display_switch_axis):
|
|
||||||
cls.draw_box(co_data, matrix)
|
|
||||||
cls.new_empty(obj, modifier)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def draw_3d_shader(cls, pos, indices, color=None, *, shader_name='3D_UNIFORM_COLOR', draw_type='LINES'):
|
def draw_3d_shader(cls, pos, indices, color=None, *, shader_name='3D_UNIFORM_COLOR', draw_type='LINES'):
|
||||||
shader = gpu.shader.from_builtin(shader_name)
|
shader = gpu.shader.from_builtin(shader_name)
|
||||||
@ -96,6 +55,8 @@ class Draw3D(GizmoUtils):
|
|||||||
|
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
|
|
||||||
|
|
||||||
|
class DrawText:
|
||||||
font_info = {
|
font_info = {
|
||||||
'font_id': 0,
|
'font_id': 0,
|
||||||
'handler': None,
|
'handler': None,
|
||||||
@ -115,7 +76,7 @@ class Draw3D(GizmoUtils):
|
|||||||
f' which will cause the deformation of the simple deformation modifier.'
|
f' which will cause the deformation of the simple deformation modifier.'
|
||||||
f' Please apply the scaling before deformation')
|
f' Please apply the scaling before deformation')
|
||||||
if obj.scale == Vector((1, 1, 1)):
|
if obj.scale == Vector((1, 1, 1)):
|
||||||
Handler.del_handler_text()
|
cls.del_handler_text()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def draw_text(cls, x, y, text='Hello Word', font_id=0, size=10, *, color=(0.5, 0.5, 0.5, 1), dpi=72, column=0):
|
def draw_text(cls, x, y, text='Hello Word', font_id=0, size=10, *, color=(0.5, 0.5, 0.5, 1), dpi=72, column=0):
|
||||||
@ -124,56 +85,62 @@ class Draw3D(GizmoUtils):
|
|||||||
blf.draw(font_id, text)
|
blf.draw(font_id, text)
|
||||||
blf.color(font_id, *color)
|
blf.color(font_id, *color)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def draw_box(cls, data, mat):
|
|
||||||
pref = cls.pref_()
|
|
||||||
coords = cls.matrix_calculation(mat,
|
|
||||||
cls.data_to_calculation(data))
|
|
||||||
cls.draw_3d_shader(coords, cls.G_INDICES, pref.bound_box_color)
|
|
||||||
|
|
||||||
@classmethod
|
class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
|
||||||
def data_to_calculation(cls, data):
|
|
||||||
((min_x, min_y, min_z), (max_x, max_y, max_z)) = data
|
|
||||||
return (
|
|
||||||
(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))
|
|
||||||
|
|
||||||
@classmethod
|
def draw(self):
|
||||||
def draw_limits_bound_box(cls):
|
gpu.state.blend_set('ALPHA')
|
||||||
|
gpu.state.line_width_set(1)
|
||||||
|
|
||||||
pref = cls.pref_()
|
gpu.state.blend_set('ALPHA')
|
||||||
handler_dit = cls.G_SimpleDeformGizmoHandlerDit
|
gpu.state.depth_test_set('ALWAYS')
|
||||||
if 'draw_limits_bound_box' in handler_dit:
|
|
||||||
# draw limits_bound_box
|
|
||||||
mat, data = handler_dit['draw_limits_bound_box']
|
|
||||||
coords = cls.matrix_calculation(mat, cls.data_to_calculation(data))
|
|
||||||
cls.draw_3d_shader(coords,
|
|
||||||
cls.G_INDICES,
|
|
||||||
pref.limits_bound_box_color)
|
|
||||||
|
|
||||||
@classmethod
|
context = bpy.context
|
||||||
def draw_limits_line(cls):
|
if self.simple_deform_public_poll(context):
|
||||||
handler_dit = cls.G_SimpleDeformGizmoHandlerDit
|
self.draw_3d(context)
|
||||||
if 'draw_line' in handler_dit:
|
|
||||||
line_pos, limits_pos, = handler_dit['draw_line']
|
def draw_3d(self, context):
|
||||||
# draw limits line
|
obj = context.object # 活动物体
|
||||||
cls.draw_3d_shader(limits_pos, ((1, 0),), (1, 1, 0, 0.5))
|
|
||||||
# draw line
|
self.draw_scale_text(obj)
|
||||||
cls.draw_3d_shader(line_pos, ((1, 0),), (1, 1, 0, 0.3))
|
if not self.modifier_origin_angle_is_available:
|
||||||
# draw pos
|
self.draw_bound_box()
|
||||||
cls.draw_3d_shader([line_pos[1]], (), (0, 1, 0, 0.5),
|
...
|
||||||
shader_name='3D_UNIFORM_COLOR', draw_type='POINTS')
|
if self.simple_deform_show_gizmo_poll(context):
|
||||||
|
# draw bound box
|
||||||
|
self.draw_bound_box()
|
||||||
|
# cls.draw_deform_mesh(obj, context)
|
||||||
|
self.draw_limits_line()
|
||||||
|
self.draw_limits_bound_box()
|
||||||
|
elif self.simple_deform_show_bend_axis_witch_poll(context):
|
||||||
|
self.draw_bound_box()
|
||||||
|
# self.new_empty(obj, modifier)
|
||||||
|
|
||||||
|
def draw_bound_box(self):
|
||||||
|
coords = self.matrix_calculation(self.obj_matrix_world,
|
||||||
|
self.tow_co_to_coordinate(self.get_bound_co_data()))
|
||||||
|
self.draw_3d_shader(coords, self.G_INDICES, self.pref.bound_box_color)
|
||||||
|
|
||||||
|
def draw_limits_bound_box(self):
|
||||||
|
self.draw_3d_shader(self.modifier_limits_bound_box,
|
||||||
|
self.G_INDICES,
|
||||||
|
self.pref.limits_bound_box_color,
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_limits_line(self):
|
||||||
|
line_pos, limits_pos, = self.modifier_limits_point
|
||||||
|
# draw limits line
|
||||||
|
self.draw_3d_shader(limits_pos, ((1, 0),), (1, 1, 0, 0.5))
|
||||||
|
# draw line
|
||||||
|
self.draw_3d_shader(line_pos, ((1, 0),), (1, 1, 0, 0.3))
|
||||||
|
# draw pos
|
||||||
|
self.draw_3d_shader([line_pos[1]], (), (0, 1, 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):
|
||||||
pref = cls.pref_()
|
pref = cls.pref_()
|
||||||
handler_dit = cls.G_SimpleDeformGizmoHandlerDit
|
handler_dit = cls.G_GizmoData
|
||||||
active = context.object.modifiers.active
|
active = context.object.modifiers.active
|
||||||
# draw deform mesh
|
# draw deform mesh
|
||||||
if 'draw' in handler_dit:
|
if 'draw' in handler_dit:
|
||||||
@ -183,8 +150,9 @@ class Draw3D(GizmoUtils):
|
|||||||
cls.draw_3d_shader(
|
cls.draw_3d_shader(
|
||||||
pos, indices, pref.deform_wireframe_color)
|
pos, indices, pref.deform_wireframe_color)
|
||||||
|
|
||||||
@classmethod
|
def draw_scale_text(self, ob):
|
||||||
def draw_scale_text(cls, ob):
|
ob = self.obj
|
||||||
if (ob.scale != Vector((1, 1, 1))) and ('handler_text' not in cls.G_SimpleDeformGizmoHandlerDit):
|
dit = self.G_GizmoData
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
if (ob.scale != Vector((1, 1, 1))) and ('handler_text' not in dit):
|
||||||
cls.draw_str, (), 'WINDOW', 'POST_PIXEL')
|
dit['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||||
|
self.draw_str, (), 'WINDOW', 'POST_PIXEL')
|
||||||
|
@ -4,7 +4,7 @@ from .angle_and_factor import AngleGizmoGroup, AngleGizmo
|
|||||||
from .bend_axis import BendAxiSwitchGizmoGroup, CustomGizmo
|
from .bend_axis import BendAxiSwitchGizmoGroup, CustomGizmo
|
||||||
from .set_deform_axis import SetDeformGizmoGroup
|
from .set_deform_axis import SetDeformGizmoGroup
|
||||||
from .up_down_limits_point import UpDownLimitsGizmo, UpDownLimitsGizmoGroup
|
from .up_down_limits_point import UpDownLimitsGizmo, UpDownLimitsGizmoGroup
|
||||||
from ..draw import Handler
|
from ..draw import Draw3D
|
||||||
|
|
||||||
class_list = (
|
class_list = (
|
||||||
UpDownLimitsGizmo,
|
UpDownLimitsGizmo,
|
||||||
@ -23,9 +23,10 @@ register_class, unregister_class = bpy.utils.register_classes_factory(class_list
|
|||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
Draw3D.add_handler()
|
||||||
register_class()
|
register_class()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
Handler.del_handler()
|
Draw3D.del_handler()
|
||||||
unregister_class()
|
unregister_class()
|
||||||
|
@ -5,10 +5,8 @@ from bpy.types import Gizmo
|
|||||||
from bpy.types import (
|
from bpy.types import (
|
||||||
GizmoGroup,
|
GizmoGroup,
|
||||||
)
|
)
|
||||||
from mathutils import Vector
|
|
||||||
|
|
||||||
from ..draw import Handler
|
from ..utils import GizmoUtils, GizmoGroupUtils
|
||||||
from ..utils import GizmoUtils
|
|
||||||
|
|
||||||
|
|
||||||
class AngleUpdate(GizmoUtils):
|
class AngleUpdate(GizmoUtils):
|
||||||
@ -26,10 +24,16 @@ class AngleUpdate(GizmoUtils):
|
|||||||
|
|
||||||
def update_gizmo_matrix(self, context):
|
def update_gizmo_matrix(self, context):
|
||||||
matrix = context.object.matrix_world
|
matrix = context.object.matrix_world
|
||||||
self.matrix_basis.translation = matrix @ Vector((self.generate_co_data()[1]))
|
point = self.get_bound_co_data()[1]
|
||||||
|
self.matrix_basis = self.obj_matrix_world
|
||||||
|
self.matrix_basis.translation = matrix @ point
|
||||||
|
|
||||||
def update_header_text(self, context):
|
def update_header_text(self, context):
|
||||||
text = self.translate_header_text('Angle', round(math.degrees(self.modifier_angle), 3))
|
if self.modifier_origin_angle_is_available:
|
||||||
|
value = round(math.degrees(self.modifier_angle), 3)
|
||||||
|
text = self.translate_header_text('Angle', value)
|
||||||
|
else:
|
||||||
|
text = self.translate_header_text('Coefficient', self.modifier.factor)
|
||||||
context.area.header_text_set(text)
|
context.area.header_text_set(text)
|
||||||
|
|
||||||
|
|
||||||
@ -46,8 +50,8 @@ class AngleGizmo(Gizmo, AngleUpdate):
|
|||||||
'draw_type',
|
'draw_type',
|
||||||
'mouse_dpi',
|
'mouse_dpi',
|
||||||
'empty_object',
|
'empty_object',
|
||||||
'init_mouse_y',
|
'init_mouse_region_y',
|
||||||
'init_mouse_x',
|
'init_mouse_region_x',
|
||||||
'custom_shape',
|
'custom_shape',
|
||||||
'int_value_angle',
|
'int_value_angle',
|
||||||
)
|
)
|
||||||
@ -64,6 +68,8 @@ class AngleGizmo(Gizmo, AngleUpdate):
|
|||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
def modal(self, context, event, tweak):
|
def modal(self, context, event, tweak):
|
||||||
|
self.clear_cache()
|
||||||
|
|
||||||
self.update_header_text(context)
|
self.update_header_text(context)
|
||||||
self.update_prop_value(event, tweak)
|
self.update_prop_value(event, tweak)
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
@ -74,24 +80,11 @@ class AngleGizmo(Gizmo, AngleUpdate):
|
|||||||
self.target_set_value('angle', self.int_value_angle)
|
self.target_set_value('angle', self.int_value_angle)
|
||||||
|
|
||||||
|
|
||||||
class AngleGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
class AngleGizmoGroup(GizmoGroup, GizmoGroupUtils):
|
||||||
"""ShowGizmo
|
"""ShowGizmo
|
||||||
"""
|
"""
|
||||||
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup'
|
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup'
|
||||||
bl_label = 'AngleGizmoGroup'
|
bl_label = 'AngleGizmoGroup'
|
||||||
bl_space_type = 'VIEW_3D'
|
|
||||||
bl_region_type = 'WINDOW'
|
|
||||||
bl_options = {'3D',
|
|
||||||
# 'SCALE',
|
|
||||||
# 'DEPTH_3D',
|
|
||||||
# 'SELECT',
|
|
||||||
'PERSISTENT',
|
|
||||||
'SHOW_MODAL_ALL',
|
|
||||||
# 'EXCLUDE_MODAL',
|
|
||||||
# 'TOOL_INIT', # not show
|
|
||||||
# 'TOOL_FALLBACK_KEYMAP',
|
|
||||||
# 'VR_REDRAWS'
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -118,7 +111,6 @@ class AngleGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
|||||||
self.generate_gizmo_mode(add_data)
|
self.generate_gizmo_mode(add_data)
|
||||||
|
|
||||||
def refresh(self, context):
|
def refresh(self, context):
|
||||||
|
|
||||||
self.angle.target_set_prop('angle',
|
self.angle.target_set_prop('angle',
|
||||||
context.object.modifiers.active,
|
context.object.modifiers.active,
|
||||||
'angle')
|
'angle')
|
||||||
|
@ -4,11 +4,10 @@ from bpy.types import GizmoGroup
|
|||||||
from bpy_types import Gizmo
|
from bpy_types import Gizmo
|
||||||
from mathutils import Euler, Vector
|
from mathutils import Euler, Vector
|
||||||
|
|
||||||
from ..draw import Handler
|
from ..utils import GizmoUtils, GizmoGroupUtils
|
||||||
from ..utils import GizmoUtils
|
|
||||||
|
|
||||||
|
|
||||||
class CustomGizmo(Gizmo, GizmoUtils, Handler):
|
class CustomGizmo(Gizmo, GizmoUtils):
|
||||||
"""绘制自定义Gizmo"""
|
"""绘制自定义Gizmo"""
|
||||||
bl_idname = '_Custom_Gizmo'
|
bl_idname = '_Custom_Gizmo'
|
||||||
draw_type: str
|
draw_type: str
|
||||||
@ -18,10 +17,9 @@ class CustomGizmo(Gizmo, GizmoUtils, Handler):
|
|||||||
self.draw_type = 'None_GizmoGroup_'
|
self.draw_type = 'None_GizmoGroup_'
|
||||||
if not hasattr(self, 'custom_shape'):
|
if not hasattr(self, 'custom_shape'):
|
||||||
self.custom_shape = {}
|
self.custom_shape = {}
|
||||||
for i in self.G_GizmoCustomShapeDict:
|
for i in self.G_CustomShape:
|
||||||
self.custom_shape[i] = self.new_custom_shape(
|
self.custom_shape[i] = self.new_custom_shape(
|
||||||
'TRIS', self.G_GizmoCustomShapeDict[i])
|
'TRIS', self.G_CustomShape[i])
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||||
@ -34,26 +32,17 @@ class CustomGizmo(Gizmo, GizmoUtils, Handler):
|
|||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
def modal(self, context, event, tweak):
|
def modal(self, context, event, tweak):
|
||||||
self.add_handler()
|
|
||||||
self.update_bound_box(context.object)
|
|
||||||
self.update_empty_matrix()
|
self.update_empty_matrix()
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
|
||||||
class BendAxiSwitchGizmoGroup(GizmoGroup, GizmoUtils):
|
class BendAxiSwitchGizmoGroup(GizmoGroup, GizmoGroupUtils):
|
||||||
"""绘制切换变型轴的
|
"""绘制切换变型轴的
|
||||||
变换方向
|
变换方向
|
||||||
"""
|
"""
|
||||||
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup_display_bend_axis_switch_gizmo'
|
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup_display_bend_axis_switch_gizmo'
|
||||||
bl_label = 'SimpleDeformGizmoGroup_display_bend_axis_switch_gizmo'
|
bl_label = 'SimpleDeformGizmoGroup_display_bend_axis_switch_gizmo'
|
||||||
|
|
||||||
bl_space_type = 'VIEW_3D'
|
|
||||||
bl_region_type = 'WINDOW'
|
|
||||||
bl_options = {
|
|
||||||
'3D',
|
|
||||||
'PERSISTENT',
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return cls.simple_deform_show_bend_axis_witch_poll(context)
|
return cls.simple_deform_show_bend_axis_witch_poll(context)
|
||||||
@ -104,7 +93,7 @@ class BendAxiSwitchGizmoGroup(GizmoGroup, GizmoUtils):
|
|||||||
def draw_prepare(self, context):
|
def draw_prepare(self, context):
|
||||||
ob = context.object
|
ob = context.object
|
||||||
mat = ob.matrix_world
|
mat = ob.matrix_world
|
||||||
top, bottom, left, right, front, back = self.each_face_pos(mat)
|
top, bottom, left, right, front, back = self.each_face_pos
|
||||||
|
|
||||||
rad = math.radians
|
rad = math.radians
|
||||||
for_list = (
|
for_list = (
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
from bpy.types import GizmoGroup
|
from bpy.types import GizmoGroup
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
|
||||||
from utils import GizmoUtils
|
from ..utils import GizmoGroupUtils
|
||||||
|
|
||||||
|
|
||||||
class SetDeformGizmoGroup(GizmoGroup, GizmoUtils):
|
class SetDeformGizmoGroup(GizmoGroup, GizmoGroupUtils):
|
||||||
bl_idname = 'OBJECT_GGT_SetDeformGizmoGroup'
|
bl_idname = 'OBJECT_GGT_SetDeformGizmoGroup'
|
||||||
bl_label = 'SetDeformGizmoGroup'
|
bl_label = 'SetDeformGizmoGroup'
|
||||||
bl_space_type = 'VIEW_3D'
|
|
||||||
bl_region_type = 'WINDOW'
|
|
||||||
bl_options = {'3D',
|
|
||||||
'PERSISTENT',
|
|
||||||
'SHOW_MODAL_ALL',
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -41,9 +35,9 @@ class SetDeformGizmoGroup(GizmoGroup, GizmoUtils):
|
|||||||
|
|
||||||
def draw_prepare(self, context):
|
def draw_prepare(self, context):
|
||||||
|
|
||||||
if 'co' in self.G_SimpleDeformGizmoHandlerDit:
|
if 'co' in self.G_GizmoData:
|
||||||
def _mat(f):
|
def _mat(f):
|
||||||
co = self.G_SimpleDeformGizmoHandlerDit['co'][0]
|
co = self.G_GizmoData['co'][0]
|
||||||
co = (co[0] + (max(self.obj.dimensions) * f), co[1],
|
co = (co[0] + (max(self.obj.dimensions) * f), co[1],
|
||||||
co[2] - (min(self.obj.dimensions) * 0.3))
|
co[2] - (min(self.obj.dimensions) * 0.3))
|
||||||
return self.obj_matrix_world @ Vector(co)
|
return self.obj_matrix_world @ Vector(co)
|
||||||
|
@ -6,11 +6,14 @@ from bpy.types import Gizmo, GizmoGroup
|
|||||||
from bpy_extras import view3d_utils
|
from bpy_extras import view3d_utils
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
|
||||||
from ..draw import Handler
|
from ..utils import GizmoUtils, GizmoGroupUtils
|
||||||
from ..utils import GizmoUtils
|
|
||||||
|
|
||||||
|
|
||||||
class GizmoProperty(GizmoUtils, Handler):
|
class GizmoProperty(GizmoUtils):
|
||||||
|
ctrl_mode: str
|
||||||
|
int_value_up_limits: int
|
||||||
|
int_value_down_limits: int
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_up_limits_mode(self):
|
def is_up_limits_mode(self):
|
||||||
return self.ctrl_mode == 'up_limits'
|
return self.ctrl_mode == 'up_limits'
|
||||||
@ -19,130 +22,145 @@ class GizmoProperty(GizmoUtils, Handler):
|
|||||||
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
|
||||||
|
def limit_scope(self):
|
||||||
|
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
|
||||||
|
def limits_min_value(self):
|
||||||
|
return self.modifier_up_limits + self.limit_scope
|
||||||
|
|
||||||
|
@property
|
||||||
|
def limits_max_value(self):
|
||||||
|
return self.modifier_up_limits - self.limit_scope
|
||||||
|
|
||||||
|
# ----get func
|
||||||
|
|
||||||
|
def get_up_limits_value(self, event):
|
||||||
|
delta = self.get_delta(event)
|
||||||
|
mid = self.middle_value + self.limit_scope
|
||||||
|
min_value = mid if self.is_middle_mode else self.limits_min_value
|
||||||
|
return self.value_limit(delta, min_value=min_value)
|
||||||
|
|
||||||
|
def get_down_limits_value(self, event):
|
||||||
|
delta = self.get_delta(event)
|
||||||
|
mid = self.middle_value - self.limit_scope
|
||||||
|
max_value = mid if self.is_middle_mode else self.limits_max_value
|
||||||
|
return self.value_limit(delta, max_value=max_value)
|
||||||
|
|
||||||
|
|
||||||
class GizmoUpdate(GizmoProperty):
|
class GizmoUpdate(GizmoProperty):
|
||||||
|
|
||||||
def update_gizmo_matrix(self, context):
|
def update_gizmo_matrix(self, context):
|
||||||
self._update_matrix_basis_to_obj()
|
self.align_orientation_to_user_perspective(context)
|
||||||
|
self.align_point_to_limits_point()
|
||||||
|
|
||||||
co = self.generate_co_data()
|
def align_orientation_to_user_perspective(self, context):
|
||||||
# calculation limits position
|
rotation = context.space_data.region_3d.view_matrix.inverted().to_quaternion()
|
||||||
top, bottom, left, right, front, back = self.each_face_pos(mat)
|
matrix = rotation.to_matrix().to_4x4()
|
||||||
(up, down), (up_, down_) = self.get_limits_pos(
|
self.matrix_basis = matrix
|
||||||
mod, (top, bottom, left, right, front, back))
|
|
||||||
self._update_matrix_basis_translation(co, mat, up_, down_)
|
|
||||||
|
|
||||||
self.up = up
|
def align_point_to_limits_point(self):
|
||||||
self.down = down
|
|
||||||
self.up_ = up_
|
|
||||||
self.down_ = down_
|
|
||||||
self.G_SimpleDeformGizmoHandlerDit['draw_line'] = (
|
|
||||||
(up, down), (up_, down_))
|
|
||||||
data = top, bottom, left, right, front, back
|
|
||||||
self.update_draw_limits_bound_box(data, mod, axis, mat, up_, down_)
|
|
||||||
|
|
||||||
def _update_matrix_basis_to_obj(self):
|
|
||||||
origin = self.modifier.origin
|
|
||||||
if origin:
|
|
||||||
self.matrix_basis = origin.matrix_world.normalized()
|
|
||||||
else:
|
|
||||||
self.matrix_basis = self.obj_matrix_world.normalized()
|
|
||||||
|
|
||||||
def _update_matrix_basis_translation(self, co, mat, up_, down_):
|
|
||||||
if self.is_up_limits_mode:
|
if self.is_up_limits_mode:
|
||||||
self.matrix_basis.translation = up_
|
self.matrix_basis.translation = self.point_limits_up
|
||||||
elif self.is_down_limits_mode:
|
elif self.is_down_limits_mode:
|
||||||
self.matrix_basis.translation = down_
|
self.matrix_basis.translation = self.point_limits_down
|
||||||
|
|
||||||
def delta_update(self, context, event, delta):
|
def delta_update(self, context, event, delta):
|
||||||
if ('draw_line' in self.G_SimpleDeformGizmoHandlerDit) and (self.ctrl_mode in ('up_limits', 'down_limits')):
|
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.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.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))
|
||||||
straight_line_distance = math.sqrt(((x2 - x) ** 2) +
|
straight_line_distance = math.sqrt(((x2 - x) ** 2) +
|
||||||
((y2 - y) ** 2))
|
((y2 - y) ** 2))
|
||||||
delta = mouse_line_distance / straight_line_distance + 0
|
delta = mouse_line_distance / straight_line_distance + 0
|
||||||
|
|
||||||
v_up = Vector((x, y))
|
v_up = Vector((x, y))
|
||||||
v_down = Vector((x2, y2))
|
v_down = Vector((x2, y2))
|
||||||
limits_angle = v_up - v_down
|
limits_angle = v_up - v_down
|
||||||
|
|
||||||
mouse_v = Vector((event.mouse_region_x, event.mouse_region_y))
|
mouse_v = Vector((event.mouse_region_x, event.mouse_region_y))
|
||||||
|
|
||||||
|
mouse_angle = mouse_v - v_down
|
||||||
|
angle_ = mouse_angle.angle(limits_angle)
|
||||||
|
if angle_ > (math.pi / 2):
|
||||||
|
delta = 0
|
||||||
|
|
||||||
mouse_angle = mouse_v - v_down
|
|
||||||
angle_ = mouse_angle.angle(limits_angle)
|
|
||||||
if angle_ > (math.pi / 2):
|
|
||||||
delta = 0
|
|
||||||
return delta
|
return delta
|
||||||
|
|
||||||
def set_down_value(self, data, mu):
|
def set_down_value(self, event):
|
||||||
up_limits, down_limits, delta, middle, min_value, max_value, limit_scope, difference_value, event, origin_mode = data
|
value = self.get_down_limits_value(event)
|
||||||
value = self.value_limit(delta, max_value=mu - limit_scope if middle else max_value)
|
|
||||||
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 + difference_value)
|
'up_limits', value + self.difference_value)
|
||||||
elif middle:
|
|
||||||
if origin_mode == 'LIMITS_MIDDLE':
|
elif self.is_middle_mode:
|
||||||
|
if self.origin_mode == 'LIMITS_MIDDLE':
|
||||||
|
mu = self.middle_value
|
||||||
self.target_set_value('up_limits', mu - (value - mu))
|
self.target_set_value('up_limits', mu - (value - mu))
|
||||||
elif 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:
|
||||||
self.target_set_value('up_limits', up_limits)
|
self.target_set_value('up_limits', self.modifier_up_limits)
|
||||||
else:
|
else:
|
||||||
self.target_set_value('up_limits', up_limits)
|
self.target_set_value('up_limits', self.modifier_up_limits)
|
||||||
|
|
||||||
def set_up_value(self, data, mu):
|
def set_up_value(self, event):
|
||||||
up_limits, down_limits, delta, middle, min_value, max_value, limit_scope, difference_value, event, origin_mode = data
|
value = self.get_up_limits_value(event)
|
||||||
value = self.value_limit(delta, min_value=mu + limit_scope if middle else min_value)
|
|
||||||
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 - difference_value)
|
'down_limits', value - self.difference_value)
|
||||||
elif middle:
|
elif self.is_middle_mode:
|
||||||
if origin_mode == 'LIMITS_MIDDLE':
|
if self.origin_mode == 'LIMITS_MIDDLE':
|
||||||
|
mu = self.middle_value
|
||||||
self.target_set_value('down_limits', mu - (value - mu))
|
self.target_set_value('down_limits', mu - (value - mu))
|
||||||
elif 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:
|
||||||
self.target_set_value('down_limits', down_limits)
|
self.target_set_value('down_limits', self.modifier_down_limits)
|
||||||
else:
|
else:
|
||||||
self.target_set_value('down_limits', down_limits)
|
self.target_set_value('down_limits', self.modifier_down_limits)
|
||||||
|
|
||||||
def set_prop_value(self, data):
|
def set_prop_value(self, event):
|
||||||
up_limits, down_limits, delta, middle, min_value, max_value, limit_scope, difference_value, event, origin_mode = data
|
if self.is_up_limits_mode:
|
||||||
mu = (up_limits + down_limits) / 2
|
self.set_up_value(event)
|
||||||
if self.is_angle_mode:
|
|
||||||
value = self.int_value_angle - delta
|
|
||||||
v = self.snap_value(value, event)
|
|
||||||
print(v)
|
|
||||||
self.target_set_value('angle', v)
|
|
||||||
elif self.is_up_limits_mode:
|
|
||||||
self.set_up_value(data, mu)
|
|
||||||
elif self.is_down_limits_mode:
|
elif self.is_down_limits_mode:
|
||||||
self.set_down_value(data, mu)
|
self.set_down_value(event)
|
||||||
|
|
||||||
def update_header_text(self, context, mod, origin, up_limits, down_limits):
|
def update_header_text(self, context):
|
||||||
translate: Callable[[Any], str] = lambda t: bpy.app.translations.pgettext(t)
|
origin = self.SimpleDeformGizmo_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
|
||||||
|
|
||||||
def t_(a, b):
|
t = self.translate_header_text
|
||||||
return translate(a) + ':{}'.format(round(b, 3))
|
text = self.translate_text(mode) + ' '
|
||||||
|
|
||||||
text = translate(mode) + ' '
|
if self.is_up_limits_mode:
|
||||||
|
value = round(self.modifier_up_limits, 3)
|
||||||
if self.modifier_is_use_angle_value and self.is_angle_mode:
|
text += t('Upper limit', value)
|
||||||
text += t_()
|
|
||||||
elif self.is_up_limits_mode:
|
|
||||||
text += t_('Upper limit', up_limits)
|
|
||||||
elif self.is_down_limits_mode:
|
elif self.is_down_limits_mode:
|
||||||
text += t_('Down limit', down_limits)
|
value = round(self.modifier_down_limits, 3)
|
||||||
else:
|
text += t('Down limit', value)
|
||||||
text += t_('Coefficient', mod.factor)
|
|
||||||
context.area.header_text_set(text)
|
context.area.header_text_set(text)
|
||||||
|
|
||||||
def event_ops(self, event, ob, origin):
|
def event_ops(self, event, ob, origin):
|
||||||
@ -161,16 +179,13 @@ class GizmoUpdate(GizmoProperty):
|
|||||||
elif event.type == 'A':
|
elif event.type == 'A':
|
||||||
self.pref.display_bend_axis_switch_gizmo = True
|
self.pref.display_bend_axis_switch_gizmo = True
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
|
||||||
class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
|
class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
|
||||||
"""显示轴向切换拖动点Gizmo(两个点)
|
|
||||||
"""
|
|
||||||
bl_idname = 'UpDownLimitsGizmo'
|
bl_idname = 'UpDownLimitsGizmo'
|
||||||
|
bl_label = 'UpDownLimitsGizmo'
|
||||||
bl_target_properties = (
|
bl_target_properties = (
|
||||||
{'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},
|
||||||
@ -183,84 +198,54 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
|
|||||||
'draw_type',
|
'draw_type',
|
||||||
'mouse_dpi',
|
'mouse_dpi',
|
||||||
'ctrl_mode',
|
'ctrl_mode',
|
||||||
'empty_object',
|
'init_mouse_region_y',
|
||||||
'init_mouse_y',
|
'init_mouse_region_x',
|
||||||
'init_mouse_x',
|
|
||||||
'custom_shape',
|
'custom_shape',
|
||||||
'value_deform_axis',
|
|
||||||
'int_value_up_limits',
|
'int_value_up_limits',
|
||||||
'int_value_down_limits',
|
'int_value_down_limits',
|
||||||
)
|
)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.generate_co_data()
|
|
||||||
self.draw_type = 'None_GizmoGroup_'
|
|
||||||
self.ctrl_mode = 'up_limits' # up_limits , down_limits
|
|
||||||
self.mouse_dpi = 10
|
self.mouse_dpi = 10
|
||||||
|
self.init_setup()
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
self.init_invoke(context, event)
|
self.init_invoke(context, event)
|
||||||
mod = context.object.modifiers.active
|
|
||||||
limits = mod.limits
|
|
||||||
up_limits = limits[1]
|
|
||||||
down_limits = limits[0]
|
|
||||||
|
|
||||||
if 'up_limits' == self.ctrl_mode:
|
if self.is_up_limits_mode:
|
||||||
self.int_value_up_limits = up_limits
|
self.int_value_up_limits = up_limits = self.modifier_up_limits
|
||||||
self.target_set_value('up_limits', self.int_value_up_limits)
|
self.target_set_value('up_limits', up_limits)
|
||||||
elif 'down_limits' == self.ctrl_mode:
|
elif self.is_down_limits_mode:
|
||||||
self.int_value_down_limits = down_limits
|
self.int_value_down_limits = down_limits = self.modifier_down_limits
|
||||||
self.target_set_value('down_limits', self.int_value_down_limits)
|
self.target_set_value('down_limits', down_limits)
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
def exit(self, context, cancel):
|
def exit(self, context, cancel):
|
||||||
context.area.header_text_set(None)
|
context.area.header_text_set(None)
|
||||||
|
|
||||||
if cancel:
|
if cancel:
|
||||||
if 'deform_axis' == self.ctrl_mode:
|
if self.is_up_limits_mode:
|
||||||
self.target_set_value('deform_axis', self.value_deform_axis)
|
|
||||||
elif 'up_limits' == self.ctrl_mode:
|
|
||||||
self.target_set_value('up_limits', self.int_value_up_limits)
|
self.target_set_value('up_limits', self.int_value_up_limits)
|
||||||
elif 'down_limits' == self.ctrl_mode:
|
elif self.is_down_limits_mode:
|
||||||
self.target_set_value(
|
self.target_set_value(
|
||||||
'down_limits', self.int_value_down_limits)
|
'down_limits', self.int_value_down_limits)
|
||||||
|
|
||||||
def modal(self, context, event, tweak):
|
def modal(self, context, event, tweak):
|
||||||
# self.update_bound_box(context.object)
|
self.clear_cache()
|
||||||
#
|
|
||||||
# ob = context.object
|
self.set_prop_value(event)
|
||||||
# mod = ob.modifiers.active
|
if self.SimpleDeformGizmo_is_use_empty_as_axis:
|
||||||
# limits = mod.limits
|
self.new_empty(self.obj, self.modifier)
|
||||||
# up_limits = limits[1]
|
# self.update_empty_matrix()
|
||||||
# down_limits = limits[0]
|
|
||||||
# origin = self.get_origin_property_group(mod, ob)
|
|
||||||
# origin_mode = origin.origin_mode
|
|
||||||
# middle = origin_mode in ('LIMITS_MIDDLE', 'MIDDLE')
|
|
||||||
# limit_scope = self.pref.modifiers_limits_tolerance
|
|
||||||
# max_value = up_limits - limit_scope
|
|
||||||
# min_value = down_limits + limit_scope
|
|
||||||
# difference_value = up_limits - down_limits
|
|
||||||
#
|
|
||||||
# delta = self.get_delta(event, tweak)
|
|
||||||
# delta = self.delta_update(context, event, delta)
|
|
||||||
#
|
|
||||||
# if origin_mode != 'NOT' and ('draw_line' in self.G_SimpleDeformGizmoHandlerDit):
|
|
||||||
# self.empty_object, _ = self.new_empty(ob, mod)
|
|
||||||
# self.G_SimpleDeformGizmoHandlerDit['empty_object'] = self.empty_object
|
|
||||||
# data = up_limits, down_limits, delta, middle, min_value, max_value, limit_scope, difference_value, event, origin_mode
|
|
||||||
# self.set_prop_value(data)
|
|
||||||
# self.update_gizmo_matrix(context)
|
|
||||||
# self.update_empty_matrix()
|
|
||||||
# self.update_bound_box(context.object)
|
|
||||||
# self.update_header_text(context, mod, origin, up_limits, down_limits)
|
# self.update_header_text(context, mod, origin, up_limits, down_limits)
|
||||||
# self.add_handler()
|
|
||||||
|
|
||||||
# return self.event_ops(event, ob, origin)
|
# return self.event_ops(event, ob, origin)
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
|
||||||
class UpDownLimitsGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
class UpDownLimitsGizmoGroup(GizmoGroup, GizmoGroupUtils):
|
||||||
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup'
|
bl_idname = 'OBJECT_GGT_UpDownLimitsGizmoGroup'
|
||||||
|
bl_label = 'UpDownLimitsGizmoGroup'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -268,8 +253,7 @@ class UpDownLimitsGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
|||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
sd_name = UpDownLimitsGizmo.bl_idname
|
sd_name = UpDownLimitsGizmo.bl_idname
|
||||||
|
gizmo_data = [
|
||||||
add_data = (
|
|
||||||
('up_limits',
|
('up_limits',
|
||||||
sd_name,
|
sd_name,
|
||||||
{'ctrl_mode': 'up_limits',
|
{'ctrl_mode': 'up_limits',
|
||||||
@ -294,10 +278,14 @@ class UpDownLimitsGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
|||||||
'use_draw_modal': True,
|
'use_draw_modal': True,
|
||||||
'scale_basis': 0.1,
|
'scale_basis': 0.1,
|
||||||
'use_draw_value': True, }),
|
'use_draw_value': True, }),
|
||||||
)
|
]
|
||||||
|
self.generate_gizmo_mode(gizmo_data)
|
||||||
|
|
||||||
def refresh(self, context):
|
def refresh(self, context):
|
||||||
pro = context.object.SimpleDeformGizmo_PropertyGroup
|
pro = context.object.SimpleDeformGizmo_PropertyGroup
|
||||||
|
for i in (self.down_limits, self.up_limits):
|
||||||
|
for j in ('down_limits', 'up_limits'):
|
||||||
|
i.target_set_prop(j, pro, j)
|
||||||
self.down_limits.target_set_prop('down_limits',
|
self.down_limits.target_set_prop('down_limits',
|
||||||
pro,
|
pro,
|
||||||
'down_limits')
|
'down_limits')
|
||||||
|
@ -47,8 +47,6 @@ class DeformAxisOperator(Operator, GizmoUtils):
|
|||||||
|
|
||||||
if not event.ctrl:
|
if not event.ctrl:
|
||||||
self.pref.display_bend_axis_switch_gizmo = False
|
self.pref.display_bend_axis_switch_gizmo = False
|
||||||
|
|
||||||
GizmoUtils.update_bound_box(context.object)
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class SimpleDeformGizmoAddonPreferences(AddonPreferences, GizmoUtils):
|
|||||||
bound_box_color: FloatVectorProperty(
|
bound_box_color: FloatVectorProperty(
|
||||||
name='Bound Box',
|
name='Bound Box',
|
||||||
description='Draw Bound Box Color',
|
description='Draw Bound Box Color',
|
||||||
default=(1, 0, 0, 0.1),
|
default=(1, 0, 0, 0.5),
|
||||||
soft_max=1,
|
soft_max=1,
|
||||||
soft_min=0,
|
soft_min=0,
|
||||||
size=4,
|
size=4,
|
||||||
|
@ -3,18 +3,22 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.app.handlers import depsgraph_update_post, persistent
|
from bpy.app.handlers import depsgraph_update_post, persistent
|
||||||
|
|
||||||
|
from .utils import GizmoUpdate
|
||||||
|
|
||||||
|
|
||||||
@persistent
|
@persistent
|
||||||
def remove_not_use_empty(scene, dep):
|
def remove_not_use_empty(scene, dep):
|
||||||
"""循环场景内的所有物体,找出没用的空物体并删掉
|
"""循环场景内的所有物体,找出没用的空物体并删掉
|
||||||
"""
|
"""
|
||||||
|
GizmoUpdate.clear_cache()
|
||||||
remove_name: str = "ViewSimpleDeformGizmo__Empty_"
|
remove_name: str = "ViewSimpleDeformGizmo__Empty_"
|
||||||
context = bpy.context
|
context = bpy.context
|
||||||
for obj in context.scene.objects:
|
if GizmoUpdate.simple_deform_modifier_is_simple(context):
|
||||||
is_empty = obj.type == "EMPTY"
|
for obj in context.scene.objects:
|
||||||
not_parent = not obj.parent
|
is_empty = obj.type == "EMPTY"
|
||||||
if remove_name in obj.name and not_parent and is_empty:
|
not_parent = not obj.parent
|
||||||
bpy.data.objects.remove(obj) # remove object
|
if remove_name in obj.name and not_parent and is_empty:
|
||||||
|
bpy.data.objects.remove(obj) # remove object
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import math
|
import math
|
||||||
import uuid
|
import uuid
|
||||||
|
from functools import cache
|
||||||
from os.path import dirname, basename, realpath
|
from os.path import dirname, basename, realpath
|
||||||
from typing import Callable, Any
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -14,8 +14,8 @@ from mathutils import Vector, Matrix, Euler
|
|||||||
class PublicData:
|
class PublicData:
|
||||||
"""Public data class, all fixed data will be placed here
|
"""Public data class, all fixed data will be placed here
|
||||||
"""
|
"""
|
||||||
G_GizmoCustomShapeDict = {}
|
G_CustomShape = {}
|
||||||
G_SimpleDeformGizmoHandlerDit = {}
|
G_GizmoData = {}
|
||||||
G_INDICES = (
|
G_INDICES = (
|
||||||
(0, 1), (0, 2), (1, 3), (2, 3),
|
(0, 1), (0, 2), (1, 3), (2, 3),
|
||||||
(4, 5), (4, 6), (5, 7), (6, 7),
|
(4, 5), (4, 6), (5, 7), (6, 7),
|
||||||
@ -47,7 +47,7 @@ class PublicData:
|
|||||||
import os
|
import os
|
||||||
json_path = os.path.join(os.path.dirname(__file__), "gizmo.json")
|
json_path = os.path.join(os.path.dirname(__file__), "gizmo.json")
|
||||||
with open(json_path, "r") as file:
|
with open(json_path, "r") as file:
|
||||||
cls.G_GizmoCustomShapeDict = json.load(file)
|
cls.G_CustomShape = json.load(file)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_mesh_get_triangle_face_co(mesh: 'bpy.types.Mesh') -> list:
|
def from_mesh_get_triangle_face_co(mesh: 'bpy.types.Mesh') -> list:
|
||||||
@ -94,32 +94,41 @@ class PublicClass(PublicData):
|
|||||||
|
|
||||||
|
|
||||||
class PublicPoll(PublicClass):
|
class PublicPoll(PublicClass):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def simple_deform_public_poll(cls, context: 'bpy.types.context') -> bool:
|
def simple_deform_modifier_is_simple(cls, context):
|
||||||
"""Public poll
|
"""
|
||||||
In 3D View
|
|
||||||
Active Object in ('MESH', 'LATTICE')
|
Active Object in ('MESH', 'LATTICE')
|
||||||
Active Modifier Type Is 'SIMPLE_DEFORM' and show_viewport
|
Active Modifier Type Is 'SIMPLE_DEFORM' and show_viewport
|
||||||
return True
|
:param context:bpy.types.Object
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
obj = context.object
|
obj = context.object
|
||||||
if not obj:
|
if not obj:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
mod = obj.modifiers.active
|
mod = obj.modifiers.active
|
||||||
if not mod:
|
if not mod:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
space = context.space_data
|
|
||||||
show_gizmo = space.show_gizmo if space.type == 'VIEW_3D' else True
|
|
||||||
|
|
||||||
available_obj_type = obj and (obj.type in ('MESH', 'LATTICE'))
|
available_obj_type = obj and (obj.type in ('MESH', 'LATTICE'))
|
||||||
available_modifiers_type = mod and (mod.type == 'SIMPLE_DEFORM')
|
available_modifiers_type = mod and (mod.type == 'SIMPLE_DEFORM')
|
||||||
is_available_obj = available_modifiers_type and available_obj_type
|
is_available_obj = available_modifiers_type and available_obj_type
|
||||||
is_obj_mode = context.mode == 'OBJECT'
|
is_obj_mode = context.mode == 'OBJECT'
|
||||||
show_mod = mod.show_viewport
|
show_mod = mod.show_viewport
|
||||||
return is_available_obj and is_obj_mode and show_gizmo and show_mod
|
return is_available_obj and is_obj_mode and show_mod
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def simple_deform_public_poll(cls, context: 'bpy.types.context') -> bool:
|
||||||
|
"""Public poll
|
||||||
|
In 3D View
|
||||||
|
return True
|
||||||
|
"""
|
||||||
|
space = context.space_data
|
||||||
|
if not space:
|
||||||
|
return False
|
||||||
|
show_gizmo = space.show_gizmo if space.type == 'VIEW_3D' else True
|
||||||
|
obj = cls.simple_deform_modifier_is_simple(context)
|
||||||
|
return obj and show_gizmo
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _simple_deform_modifier_is_bend_poll(cls, context):
|
def _simple_deform_modifier_is_bend_poll(cls, context):
|
||||||
@ -250,12 +259,14 @@ class PublicUtils(PublicPoll):
|
|||||||
b = mat @ Vector((max_x, min_y, min_z))
|
b = mat @ Vector((max_x, min_y, min_z))
|
||||||
c = mat @ Vector((min_x, max_y, min_z))
|
c = mat @ Vector((min_x, max_y, min_z))
|
||||||
d = mat @ Vector((min_x, min_y, max_z))
|
d = mat @ Vector((min_x, min_y, max_z))
|
||||||
return ((aa + bb) / Vector((2, 2, 2)) for aa, bb in ((a, d)
|
point_list = ((a, d),
|
||||||
(c, b)
|
(c, b),
|
||||||
(c, d)
|
(c, d),
|
||||||
(a, b)
|
(a, b),
|
||||||
(d, b)
|
(d, b),
|
||||||
(c, a)))
|
(c, a),)
|
||||||
|
|
||||||
|
return list((aa + bb) / 2 for (aa, bb) in point_list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def translate_text(cls, text):
|
def translate_text(cls, text):
|
||||||
@ -267,35 +278,6 @@ class PublicUtils(PublicPoll):
|
|||||||
|
|
||||||
|
|
||||||
class GizmoClassMethod(PublicUtils):
|
class GizmoClassMethod(PublicUtils):
|
||||||
@classmethod
|
|
||||||
def get_origin_property_group(cls, mod, ob):
|
|
||||||
if mod.origin:
|
|
||||||
return mod.origin.SimpleDeformGizmo_PropertyGroup
|
|
||||||
else:
|
|
||||||
return ob.SimpleDeformGizmo_PropertyGroup
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_up_down_return_list(cls, mod, axis, up_, down_, data):
|
|
||||||
top, bottom, left, right, front, back = data
|
|
||||||
if 'BEND' == mod.deform_method:
|
|
||||||
if axis in ('X', 'Y'):
|
|
||||||
top = up_
|
|
||||||
bottom = down_
|
|
||||||
elif axis == 'Z':
|
|
||||||
right = up_
|
|
||||||
left = down_
|
|
||||||
else:
|
|
||||||
if axis == 'X':
|
|
||||||
right = up_
|
|
||||||
left = down_
|
|
||||||
elif axis == 'Y':
|
|
||||||
back = up_
|
|
||||||
front = down_
|
|
||||||
elif axis == 'Z':
|
|
||||||
top = up_
|
|
||||||
bottom = down_
|
|
||||||
return top, bottom, left, right, front, back
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_empty(cls, obj, mod):
|
def new_empty(cls, obj, mod):
|
||||||
origin = mod.origin
|
origin = mod.origin
|
||||||
@ -355,52 +337,6 @@ class GizmoClassMethod(PublicUtils):
|
|||||||
elif origin_mode == 'MIDDLE':
|
elif origin_mode == 'MIDDLE':
|
||||||
empty_object.matrix_world.translation = (up + down) / tow
|
empty_object.matrix_world.translation = (up + down) / tow
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_up_down(cls, mod, axis, top, bottom, left, right, front, back):
|
|
||||||
if 'BEND' == mod.deform_method:
|
|
||||||
if axis in ('X', 'Y'):
|
|
||||||
return top, bottom
|
|
||||||
elif axis == 'Z':
|
|
||||||
return right, left
|
|
||||||
else:
|
|
||||||
if axis == 'X':
|
|
||||||
return right, left
|
|
||||||
elif axis == 'Y':
|
|
||||||
return back, front
|
|
||||||
elif axis == 'Z':
|
|
||||||
return top, bottom
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_limits_pos(cls, mod, data):
|
|
||||||
top, bottom, left, right, front, back = data
|
|
||||||
up_limits = mod.limits[1]
|
|
||||||
down_limits = mod.limits[0]
|
|
||||||
axis = mod.deform_axis
|
|
||||||
|
|
||||||
if mod.origin:
|
|
||||||
vector_axis = cls.get_vector_axis(mod)
|
|
||||||
origin_mat = mod.origin.matrix_world.to_3x3()
|
|
||||||
axis_ = origin_mat @ vector_axis
|
|
||||||
point_lit = [[top, bottom], [left, right], [front, back]]
|
|
||||||
|
|
||||||
for f in range(point_lit.__len__()):
|
|
||||||
i = point_lit[f][0]
|
|
||||||
j = point_lit[f][1]
|
|
||||||
angle = cls.point_to_angle(i, j, f, axis_)
|
|
||||||
if abs(angle - 180) < 0.00001:
|
|
||||||
up, down = j, i
|
|
||||||
elif abs(angle) < 0.00001:
|
|
||||||
up, down = i, j
|
|
||||||
else:
|
|
||||||
up, down = cls.get_up_down(mod, axis, top, bottom,
|
|
||||||
left, right, front, back)
|
|
||||||
|
|
||||||
ex = lambda a: down + ((up - down) * Vector((a, a, a)))
|
|
||||||
|
|
||||||
up_ = ex(up_limits)
|
|
||||||
down_ = ex(down_limits)
|
|
||||||
return (up, down), (up_, down_)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_vector_axis(cls, mod):
|
def get_vector_axis(cls, mod):
|
||||||
axis = mod.deform_axis
|
axis = mod.deform_axis
|
||||||
@ -415,151 +351,44 @@ class GizmoClassMethod(PublicUtils):
|
|||||||
return vector_axis
|
return vector_axis
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_co_data(cls):
|
def get_bound_co_data(cls):
|
||||||
handler_dit = cls.G_SimpleDeformGizmoHandlerDit
|
if 'co' not in cls.G_GizmoData:
|
||||||
|
cls.G_GizmoData['co'] = cls.get_mesh_max_min_co(
|
||||||
if 'co' not in handler_dit:
|
|
||||||
handler_dit['co'] = cls.get_mesh_max_min_co(
|
|
||||||
bpy.context.object)
|
bpy.context.object)
|
||||||
return handler_dit['co']
|
return cls.G_GizmoData['co']
|
||||||
|
|
||||||
|
|
||||||
class GizmoUpdate(GizmoClassMethod):
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_matrix(cls, mod, ob):
|
def tow_co_to_coordinate(cls, data):
|
||||||
if mod.deform_method == 'BEND':
|
((min_x, min_y, min_z), (max_x, max_y, max_z)) = data
|
||||||
cls.new_empty(ob, mod)
|
return (
|
||||||
if mod.origin:
|
Vector((max_x, min_y, min_z)),
|
||||||
empty_object = mod.origin
|
Vector((min_x, min_y, min_z)),
|
||||||
modifiers_co = cls.G_SimpleDeformGizmoHandlerDit['modifiers_co']
|
Vector((max_x, max_y, min_z)),
|
||||||
for index, mod_name in enumerate(modifiers_co):
|
Vector((min_x, max_y, min_z)),
|
||||||
co_items = list(modifiers_co.items())
|
Vector((max_x, min_y, max_z)),
|
||||||
if mod.name == mod_name:
|
Vector((min_x, min_y, max_z)),
|
||||||
data = co_items[index - 1][1] if (
|
Vector((max_x, max_y, max_z)),
|
||||||
index or (index != 1)) else modifiers_co['co']
|
Vector((min_x, max_y, max_z))
|
||||||
(up, down), (up_, down_) = cls.get_limits_pos(
|
)
|
||||||
mod, cls.co_to_direction(ob.matrix_world.copy(), data))
|
|
||||||
origin_mode = cls.get_origin_property_group(
|
|
||||||
mod, ob).origin_mode
|
|
||||||
cls.set_empty_obj_matrix(
|
|
||||||
origin_mode, empty_object, up_, down_, up, down)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_empty_matrix(cls):
|
|
||||||
ob = bpy.context.object
|
|
||||||
for mod in ob.modifiers:
|
|
||||||
if mod.type == 'SIMPLE_DEFORM':
|
|
||||||
cls.update_matrix(mod, ob)
|
|
||||||
|
|
||||||
@classmethod
|
class PublicProperty(GizmoClassMethod):
|
||||||
def update_bound_box(cls, obj: 'bpy.types.Object'):
|
|
||||||
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):
|
def __from_up_down_point_get_limits_point(self, up_point, down_point):
|
||||||
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)
|
def ex(a):
|
||||||
|
return down_point + ((up_point - down_point) * Vector((a, a, a)))
|
||||||
|
|
||||||
cls.link_obj_to_active_collection(new_object)
|
up_limits = ex(self.modifier_up_limits)
|
||||||
|
down_limits = ex(self.modifier_down_limits)
|
||||||
|
return up_limits, down_limits
|
||||||
|
|
||||||
if new_object.parent != obj:
|
@cache
|
||||||
new_object.parent = obj
|
def _get_limits_point_and_bound_box_co(self):
|
||||||
|
top, bottom, left, right, front, back = self.each_face_pos
|
||||||
new_object.modifiers.clear()
|
mod = self.modifier
|
||||||
subdivision = new_object.modifiers.new('1', 'SUBSURF')
|
g_l = self.__from_up_down_point_get_limits_point
|
||||||
subdivision.levels = 7
|
if self.modifier.origin:
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['modifiers_co'] = {}
|
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['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_SimpleDeformGizmoHandlerDit['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_SimpleDeformGizmoHandlerDit:
|
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['numpy_data'] = {}
|
|
||||||
|
|
||||||
numpy_data = cls.G_SimpleDeformGizmoHandlerDit['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_SimpleDeformGizmoHandlerDit['draw'] = (ver, indices, matrix, modifiers, limits)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_co_data(cls, ob, mod):
|
|
||||||
handler_dit = cls.G_SimpleDeformGizmoHandlerDit
|
|
||||||
|
|
||||||
if 'modifiers_co' in cls.G_SimpleDeformGizmoHandlerDit and ob.type in ('MESH', 'LATTICE'):
|
|
||||||
modifiers_co = cls.G_SimpleDeformGizmoHandlerDit['modifiers_co']
|
|
||||||
for index, mod_name in enumerate(modifiers_co):
|
|
||||||
co_items = list(modifiers_co.items())
|
|
||||||
if mod.name == mod_name:
|
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['co'] = co_items[index - 1][1] if (index or (index != 1)) else \
|
|
||||||
modifiers_co['co']
|
|
||||||
|
|
||||||
def update_draw_limits_bound_box(self, data, mod, axis, mat, up_, down_):
|
|
||||||
top, bottom, left, right, front, back = data
|
|
||||||
if mod.origin:
|
|
||||||
vector_axis = self.get_vector_axis(mod)
|
vector_axis = self.get_vector_axis(mod)
|
||||||
origin_mat = mod.origin.matrix_world.to_3x3()
|
origin_mat = mod.origin.matrix_world.to_3x3()
|
||||||
axis_ = origin_mat @ vector_axis
|
axis_ = origin_mat @ vector_axis
|
||||||
@ -569,37 +398,86 @@ class GizmoUpdate(GizmoClassMethod):
|
|||||||
j = point_lit[f][1]
|
j = point_lit[f][1]
|
||||||
angle = self.point_to_angle(i, j, f, axis_)
|
angle = self.point_to_angle(i, j, f, axis_)
|
||||||
if abs(angle - 180) < 0.00001:
|
if abs(angle - 180) < 0.00001:
|
||||||
point_lit[f][1], point_lit[f][0] = up_, down_
|
up_point, down_point = j, i
|
||||||
|
up_limits, down_limits = g_l(j, i)
|
||||||
|
point_lit[f][1], point_lit[f][0] = up_limits, down_limits
|
||||||
elif abs(angle) < 0.00001:
|
elif abs(angle) < 0.00001:
|
||||||
point_lit[f][0], point_lit[f][1] = up_, down_
|
up_point, down_point = i, j
|
||||||
|
up_limits, down_limits = g_l(i, j)
|
||||||
|
point_lit[f][0], point_lit[f][1] = up_limits, down_limits
|
||||||
|
|
||||||
[[top, bottom], [left, right], [front, back]] = point_lit
|
[[top, bottom], [left, right], [front, back]] = point_lit
|
||||||
else:
|
else:
|
||||||
top, bottom, left, right, front, back = self.get_up_down_return_list(
|
axis = self.modifier_deform_axis
|
||||||
mod, axis, up_, down_, data)
|
if 'BEND' == self.modifier.deform_method:
|
||||||
data = top, bottom, left, right, front, back
|
if axis in ('X', 'Y'):
|
||||||
(top, bottom, left, right, front,
|
up_point, down_point = top, bottom
|
||||||
back) = self.matrix_calculation(mat.inverted(), data)
|
top, bottom = up_limits, down_limits = g_l(top, bottom)
|
||||||
self.G_SimpleDeformGizmoHandlerDit['draw_limits_bound_box'] = (
|
elif axis == 'Z':
|
||||||
mat, ((right[0], back[1], top[2]), (left[0], front[1], bottom[2],)))
|
up_point, down_point = right, left
|
||||||
|
right, left = up_limits, down_limits = g_l(right, left)
|
||||||
|
else:
|
||||||
|
if axis == 'X':
|
||||||
|
up_point, down_point = right, left
|
||||||
|
right, left = up_limits, down_limits = g_l(right, left)
|
||||||
|
elif axis == 'Y':
|
||||||
|
up_point, down_point = back, front
|
||||||
|
back, front = up_limits, down_limits = g_l(back, front)
|
||||||
|
|
||||||
def update_bound_box_wireframe(self):
|
elif axis == 'Z':
|
||||||
...
|
up_point, down_point = top, bottom
|
||||||
|
top, bottom = up_limits, down_limits = g_l(top, bottom)
|
||||||
|
|
||||||
def update_up_down_limits_wireframe(self):
|
(top, bottom, left,
|
||||||
...
|
right, front, back) = self.matrix_calculation(self.obj_matrix_world.inverted(),
|
||||||
|
(top, bottom, left, right, front, back))
|
||||||
|
|
||||||
def update_deform_wireframe(self):
|
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
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
class PublicProperty(GizmoUpdate):
|
@cache
|
||||||
|
def _each_face_pos(self, mat):
|
||||||
|
return self.co_to_direction(mat, self.get_bound_co_data())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def each_face_pos(cls, mat: 'Matrix' = None):
|
def clear_cache(cls):
|
||||||
if mat is None:
|
cls._each_face_pos.cache_clear()
|
||||||
mat = Matrix()
|
cls._get_limits_point_and_bound_box_co.cache_clear()
|
||||||
return cls.co_to_direction(mat, cls.G_SimpleDeformGizmoHandlerDit['co'])
|
cls.clear_data()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_data(cls):
|
||||||
|
cls.G_GizmoData.clear()
|
||||||
|
|
||||||
|
# --------------- Cache Data ----------------------
|
||||||
|
|
||||||
|
@property
|
||||||
|
def each_face_pos(self):
|
||||||
|
return self._each_face_pos(self.obj_matrix_world)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_limits_point(self):
|
||||||
|
points, _ = self._get_limits_point_and_bound_box_co()
|
||||||
|
return points
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_limits_bound_box(self):
|
||||||
|
_, bound = self._get_limits_point_and_bound_box_co()
|
||||||
|
return bound
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_origin_angle_is_available(self):
|
||||||
|
try:
|
||||||
|
self._get_limits_point_and_bound_box_co()
|
||||||
|
return True
|
||||||
|
except UnboundLocalError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# --------------- Compute Data ----------------------
|
||||||
@property
|
@property
|
||||||
def obj(self):
|
def obj(self):
|
||||||
return bpy.context.object
|
return bpy.context.object
|
||||||
@ -607,7 +485,12 @@ class PublicProperty(GizmoUpdate):
|
|||||||
@property
|
@property
|
||||||
def obj_matrix_world(self):
|
def obj_matrix_world(self):
|
||||||
if self.obj:
|
if self.obj:
|
||||||
return self.obj.matrix_world
|
mat = self.obj.matrix_world.copy()
|
||||||
|
mat.freeze()
|
||||||
|
return mat
|
||||||
|
mat = Matrix()
|
||||||
|
mat.freeze()
|
||||||
|
return mat
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def modifier(self):
|
def modifier(self):
|
||||||
@ -628,64 +511,185 @@ class PublicProperty(GizmoUpdate):
|
|||||||
if mod:
|
if mod:
|
||||||
return mod.angle
|
return mod.angle
|
||||||
|
|
||||||
@property
|
|
||||||
def active_modifier_is_simple_deform(self):
|
|
||||||
return self.modifier and self.modifier.type == 'SIMPLE_DEFORM'
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def modifier_is_use_angle_value(self):
|
def modifier_is_use_angle_value(self):
|
||||||
if self.active_modifier_is_simple_deform:
|
if self.active_modifier_is_simple_deform:
|
||||||
return self.modifier.deform_method in ('TWIST', 'BEND')
|
return self.modifier.deform_method in ('TWIST', 'BEND')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_up_limits(self):
|
||||||
|
if self.modifier:
|
||||||
|
return self.modifier.limits[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_down_limits(self):
|
||||||
|
if self.modifier:
|
||||||
|
return self.modifier.limits[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_modifier_is_simple_deform(self):
|
||||||
|
return self.modifier and self.modifier.type == 'SIMPLE_DEFORM'
|
||||||
|
|
||||||
|
# ----- point
|
||||||
@property
|
@property
|
||||||
def point_up(self):
|
def point_up(self):
|
||||||
...
|
return self.modifier_limits_point[0][0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_down(self):
|
def point_down(self):
|
||||||
...
|
return self.modifier_limits_point[0][1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_limits_up(self):
|
def point_limits_up(self):
|
||||||
...
|
return self.modifier_limits_point[1][0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_limits_down(self):
|
def point_limits_down(self):
|
||||||
...
|
return self.modifier_limits_point[1][1]
|
||||||
|
|
||||||
|
# ------
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_top(self):
|
def SimpleDeformGizmo_origin_property_group(self):
|
||||||
...
|
mod = self.modifier
|
||||||
|
if mod.origin:
|
||||||
|
return mod.origin.SimpleDeformGizmo_PropertyGroup
|
||||||
|
else:
|
||||||
|
return self.obj.SimpleDeformGizmo_PropertyGroup
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_bottom(self):
|
def SimpleDeformGizmo_is_use_empty_as_axis(self):
|
||||||
...
|
return self.SimpleDeformGizmo_origin_property_group.origin_mode != 'NOT'
|
||||||
|
|
||||||
@property
|
|
||||||
def point_left(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
@property
|
class GizmoUpdate(PublicProperty):
|
||||||
def point_right(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
@property
|
|
||||||
def point_front(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
@property
|
|
||||||
def point_back(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_cache(cls):
|
def update_matrix(cls, mod, ob):
|
||||||
|
if mod.deform_method == 'BEND':
|
||||||
|
cls.new_empty(ob, mod)
|
||||||
|
if mod.origin:
|
||||||
|
empty_object = mod.origin
|
||||||
|
modifiers_co = cls.G_GizmoData['modifiers_co']
|
||||||
|
for index, mod_name in enumerate(modifiers_co):
|
||||||
|
co_items = list(modifiers_co.items())
|
||||||
|
if mod.name == mod_name:
|
||||||
|
data = co_items[index - 1][1] if (
|
||||||
|
index or (index != 1)) else modifiers_co['co']
|
||||||
|
(up, down), (up_, down_) = cls.get_limits_pos(
|
||||||
|
mod, cls.co_to_direction(ob.matrix_world.copy(), data))
|
||||||
|
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
|
||||||
|
# def update_empty_matrix(cls):
|
||||||
|
# ob = bpy.context.object
|
||||||
|
# for mod in ob.modifiers:
|
||||||
|
# if mod.type == 'SIMPLE_DEFORM':
|
||||||
|
# cls.update_matrix(mod, ob)
|
||||||
|
#
|
||||||
|
# @classmethod
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
def update_deform_wireframe(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
class GizmoUtils(PublicProperty):
|
class GizmoUtils(GizmoUpdate):
|
||||||
custom_shape: dict
|
custom_shape: dict
|
||||||
init_mouse_y: float
|
init_mouse_region_y: float
|
||||||
init_mouse_x: float
|
init_mouse_region_x: float
|
||||||
mouse_dpi: int
|
mouse_dpi: int
|
||||||
matrix_basis: Matrix
|
matrix_basis: Matrix
|
||||||
draw_type: str
|
draw_type: str
|
||||||
@ -710,33 +714,35 @@ class GizmoUtils(PublicProperty):
|
|||||||
def init_shape(self):
|
def init_shape(self):
|
||||||
if not hasattr(self, 'custom_shape'):
|
if not hasattr(self, 'custom_shape'):
|
||||||
self.custom_shape = {}
|
self.custom_shape = {}
|
||||||
for i in self.G_GizmoCustomShapeDict:
|
for i in self.G_CustomShape:
|
||||||
item = self.G_GizmoCustomShapeDict[i]
|
item = self.G_CustomShape[i]
|
||||||
self.custom_shape[i] = self.new_custom_shape('TRIS', item)
|
self.custom_shape[i] = self.new_custom_shape('TRIS', item)
|
||||||
|
|
||||||
def init_setup(self):
|
def init_setup(self):
|
||||||
self.init_shape()
|
self.init_shape()
|
||||||
|
|
||||||
def init_invoke(self, context, event):
|
def init_invoke(self, context, event):
|
||||||
self.init_mouse_y = event.mouse_y
|
self.init_mouse_region_y = event.mouse_region_y
|
||||||
self.init_mouse_x = event.mouse_x
|
self.init_mouse_region_x = event.mouse_region_x
|
||||||
|
|
||||||
def _update_matrix(self, context):
|
def _update_matrix(self, context):
|
||||||
func = getattr(self, 'update_gizmo_matrix', None)
|
func = getattr(self, 'update_gizmo_matrix', None)
|
||||||
if func:
|
if func and self.modifier_origin_angle_is_available:
|
||||||
func(context)
|
func(context)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
if self.modifier_origin_angle_is_available:
|
||||||
self._update_matrix(context)
|
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||||
|
self._update_matrix(context)
|
||||||
|
|
||||||
def draw_select(self, context, select_id):
|
def draw_select(self, context, select_id):
|
||||||
self.draw_custom_shape(
|
if self.modifier_origin_angle_is_available:
|
||||||
self.custom_shape[self.draw_type], select_id=select_id)
|
self.draw_custom_shape(
|
||||||
self._update_matrix(context)
|
self.custom_shape[self.draw_type], select_id=select_id)
|
||||||
|
self._update_matrix(context)
|
||||||
|
|
||||||
def get_delta(self, event):
|
def get_delta(self, event):
|
||||||
delta = (self.init_mouse_x - event.mouse_x) / self.mouse_dpi
|
delta = (self.init_mouse_region_x - event.mouse_region_x) / self.mouse_dpi
|
||||||
return delta
|
return delta
|
||||||
|
|
||||||
def get_snap(self, delta, tweak):
|
def get_snap(self, delta, tweak):
|
||||||
@ -759,6 +765,22 @@ class GizmoUtils(PublicProperty):
|
|||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class GizmoGroupUtils(GizmoUtils):
|
||||||
|
bl_space_type = 'VIEW_3D'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_options = {'3D',
|
||||||
|
'PERSISTENT',
|
||||||
|
# 'SCALE',
|
||||||
|
# 'DEPTH_3D',
|
||||||
|
# 'SELECT',
|
||||||
|
# 'SHOW_MODAL_ALL',
|
||||||
|
# 'EXCLUDE_MODAL',
|
||||||
|
# 'TOOL_INIT', # not show
|
||||||
|
# 'TOOL_FALLBACK_KEYMAP',
|
||||||
|
# 'VR_REDRAWS'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Tmp:
|
class Tmp:
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_origin_bounds(cls, obj: 'bpy.types.Object') -> list:
|
def get_origin_bounds(cls, obj: 'bpy.types.Object') -> list:
|
||||||
|
Loading…
Reference in New Issue
Block a user