new addon simple_deform_helper #104464
@ -5,7 +5,7 @@ import gpu
|
|||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
|
||||||
from .utils import PublicUtils
|
from .utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class Handler:
|
class Handler:
|
||||||
@ -39,7 +39,48 @@ class Handler:
|
|||||||
cls.G_SimpleDeformGizmoHandlerDit.clear()
|
cls.G_SimpleDeformGizmoHandlerDit.clear()
|
||||||
|
|
||||||
|
|
||||||
class Draw3D(PublicUtils):
|
class Draw3D(GizmoUtils):
|
||||||
|
|
||||||
|
@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)
|
||||||
@ -86,8 +127,8 @@ class Draw3D(PublicUtils):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def draw_box(cls, data, mat):
|
def draw_box(cls, data, mat):
|
||||||
pref = cls.pref_()
|
pref = cls.pref_()
|
||||||
coords = PublicUtils.matrix_calculation(mat,
|
coords = cls.matrix_calculation(mat,
|
||||||
cls.data_to_calculation(data))
|
cls.data_to_calculation(data))
|
||||||
cls.draw_3d_shader(coords, cls.G_INDICES, pref.bound_box_color)
|
cls.draw_3d_shader(coords, cls.G_INDICES, pref.bound_box_color)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -111,7 +152,7 @@ class Draw3D(PublicUtils):
|
|||||||
if 'draw_limits_bound_box' in handler_dit:
|
if 'draw_limits_bound_box' in handler_dit:
|
||||||
# draw limits_bound_box
|
# draw limits_bound_box
|
||||||
mat, data = handler_dit['draw_limits_bound_box']
|
mat, data = handler_dit['draw_limits_bound_box']
|
||||||
coords = PublicUtils.matrix_calculation(mat, cls.data_to_calculation(data))
|
coords = cls.matrix_calculation(mat, cls.data_to_calculation(data))
|
||||||
cls.draw_3d_shader(coords,
|
cls.draw_3d_shader(coords,
|
||||||
cls.G_INDICES,
|
cls.G_INDICES,
|
||||||
pref.limits_bound_box_color)
|
pref.limits_bound_box_color)
|
||||||
@ -147,43 +188,3 @@ class Draw3D(PublicUtils):
|
|||||||
if (ob.scale != Vector((1, 1, 1))) and ('handler_text' not in cls.G_SimpleDeformGizmoHandlerDit):
|
if (ob.scale != Vector((1, 1, 1))) and ('handler_text' not in cls.G_SimpleDeformGizmoHandlerDit):
|
||||||
cls.G_SimpleDeformGizmoHandlerDit['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
cls.G_SimpleDeformGizmoHandlerDit['handler_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||||
cls.draw_str, (), 'WINDOW', 'POST_PIXEL')
|
cls.draw_str, (), 'WINDOW', 'POST_PIXEL')
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def is_draw_box(cls, context):
|
|
||||||
obj = context.object # 活动物体
|
|
||||||
matrix = obj.matrix_world # 活动物体矩阵
|
|
||||||
modifier = context.object.modifiers.active # 活动修改器
|
|
||||||
|
|
||||||
pref = cls.pref_()
|
|
||||||
simple_poll = PublicUtils.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)
|
|
||||||
PublicUtils.update_co_data(obj, modifier)
|
|
||||||
|
|
||||||
co_data = PublicUtils.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)
|
|
||||||
PublicUtils.new_empty(obj, modifier)
|
|
||||||
|
|
||||||
@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 PublicUtils.simple_deform_public_poll(context):
|
|
||||||
cls.is_draw_box(context)
|
|
||||||
else:
|
|
||||||
Handler.del_handler()
|
|
||||||
|
@ -1,87 +1,20 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy_types import Gizmo
|
from bpy_types import Gizmo
|
||||||
|
|
||||||
from draw import Handler
|
from .bend_axis import SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo, CustomGizmo
|
||||||
from utils import PublicUtils
|
from .up_down_limits_point import GizmoProperty, UpDownLimitsGizmo
|
||||||
|
from .angle_and_factor import AngleGizmoGroup, AngleGizmo
|
||||||
|
from ..draw import Handler
|
||||||
class GizmoProperty:
|
|
||||||
|
|
||||||
@property
|
|
||||||
def obj(self):
|
|
||||||
return bpy.context.object
|
|
||||||
|
|
||||||
@property
|
|
||||||
def modifier(self):
|
|
||||||
obj = self.obj
|
|
||||||
if not obj:
|
|
||||||
return
|
|
||||||
return obj.modifiers.active
|
|
||||||
|
|
||||||
@property
|
|
||||||
def active_modifier_is_simple_deform(self):
|
|
||||||
return self.modifier and self.modifier.type == 'SIMPLE_DEFORM'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_use_angle_value(self):
|
|
||||||
if self.active_modifier_is_simple_deform:
|
|
||||||
return self.modifier.deform_method in ('TWIST', 'BEND')
|
|
||||||
|
|
||||||
|
|
||||||
class GizmoPublic(GizmoProperty, PublicUtils, Handler):
|
|
||||||
def generate_gizmo_mode(self, gizmo_data):
|
|
||||||
"""生成gizmo的上限下限及角度设置
|
|
||||||
|
|
||||||
Args:
|
|
||||||
gizmo_data (_type_): _description_
|
|
||||||
"""
|
|
||||||
for i, j, k in gizmo_data:
|
|
||||||
setattr(self, i, self.gizmos.new(j))
|
|
||||||
gizmo = getattr(self, i)
|
|
||||||
for f in k:
|
|
||||||
if f == 'target_set_operator':
|
|
||||||
gizmo.target_set_operator(k[f])
|
|
||||||
elif f == 'target_set_prop':
|
|
||||||
gizmo.target_set_prop(*k[f])
|
|
||||||
else:
|
|
||||||
setattr(gizmo, f, k[f])
|
|
||||||
|
|
||||||
|
|
||||||
class CustomGizmo(Gizmo, PublicUtils, Handler):
|
|
||||||
"""绘制自定义Gizmo"""
|
|
||||||
bl_idname = '_Custom_Gizmo'
|
|
||||||
draw_type: str
|
|
||||||
custom_shape: dict
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
self.draw_type = 'None_GizmoGroup_'
|
|
||||||
if not hasattr(self, 'custom_shape'):
|
|
||||||
self.custom_shape = {}
|
|
||||||
for i in self.G_GizmoCustomShapeDict:
|
|
||||||
self.custom_shape[i] = self.new_custom_shape(
|
|
||||||
'TRIS', self.G_GizmoCustomShapeDict[i])
|
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
|
||||||
|
|
||||||
def draw_select(self, context, select_id):
|
|
||||||
self.draw_custom_shape(
|
|
||||||
self.custom_shape[self.draw_type], select_id=select_id)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
|
||||||
return {'RUNNING_MODAL'}
|
|
||||||
|
|
||||||
def modal(self, context, event, tweak):
|
|
||||||
self.add_handler()
|
|
||||||
self.update_bound_box(context.object)
|
|
||||||
self.update_empty_matrix()
|
|
||||||
return {'RUNNING_MODAL'}
|
|
||||||
|
|
||||||
|
|
||||||
class_list = (
|
class_list = (
|
||||||
ViewSimpleDeformGizmo,
|
# GizmoProperty,
|
||||||
SimpleDeformGizmoGroup,
|
# UpDownLimitsGizmo,
|
||||||
|
|
||||||
|
AngleGizmo,
|
||||||
|
AngleGizmoGroup,
|
||||||
|
|
||||||
|
CustomGizmo,
|
||||||
|
SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo,
|
||||||
)
|
)
|
||||||
|
|
||||||
register_class, unregister_class = bpy.utils.register_classes_factory(class_list)
|
register_class, unregister_class = bpy.utils.register_classes_factory(class_list)
|
||||||
|
163
simple_deform_helper/gizmo/angle_and_factor.py
Normal file
163
simple_deform_helper/gizmo/angle_and_factor.py
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
import math
|
||||||
|
|
||||||
|
from bpy.types import (
|
||||||
|
GizmoGroup,
|
||||||
|
)
|
||||||
|
from bpy.types import Gizmo
|
||||||
|
from mathutils import Vector, Euler, Matrix
|
||||||
|
|
||||||
|
from ..utils import GizmoUtils
|
||||||
|
from ..draw import Handler
|
||||||
|
|
||||||
|
|
||||||
|
class AngleGizmo(Gizmo, GizmoUtils):
|
||||||
|
bl_idname = 'ViewSimpleAngleGizmo'
|
||||||
|
|
||||||
|
bl_target_properties = (
|
||||||
|
{'id': 'up_limits', 'type': 'FLOAT', 'array_length': 1},
|
||||||
|
{'id': 'down_limits', 'type': 'FLOAT', 'array_length': 1},
|
||||||
|
{'id': 'angle', 'type': 'FLOAT', 'array_length': 1},
|
||||||
|
)
|
||||||
|
|
||||||
|
__slots__ = (
|
||||||
|
'draw_type',
|
||||||
|
'mouse_dpi',
|
||||||
|
'empty_object',
|
||||||
|
'init_mouse_y',
|
||||||
|
'init_mouse_x',
|
||||||
|
'custom_shape',
|
||||||
|
'int_value_angle',
|
||||||
|
'rotate_follow_modifier',
|
||||||
|
)
|
||||||
|
|
||||||
|
int_value_angle: float
|
||||||
|
rotate_follow_modifier: bool
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.mouse_dpi = 2
|
||||||
|
self.rotate_follow_modifier = True
|
||||||
|
self.init_setup()
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
self.init_invoke(context, event)
|
||||||
|
self.int_value_angle = self.target_get_value('angle')
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def modal(self, context, event, tweak):
|
||||||
|
self.update_header_text(context)
|
||||||
|
self.update_prop_value(event, tweak)
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def exit(self, context, cancel):
|
||||||
|
context.area.header_text_set(None)
|
||||||
|
if cancel:
|
||||||
|
self.target_set_value('angle', self.int_value_angle)
|
||||||
|
|
||||||
|
def update_prop_value(self, event, tweak):
|
||||||
|
# radians 弧度
|
||||||
|
# degrees 角度
|
||||||
|
delta = self.get_delta(event)
|
||||||
|
value = math.degrees(self.int_value_angle - delta)
|
||||||
|
new_value = (self.get_snap(value, tweak))
|
||||||
|
old_value = math.degrees(self.target_get_value('angle'))
|
||||||
|
|
||||||
|
print(new_value, old_value)
|
||||||
|
self.target_set_value('angle', math.radians(new_value))
|
||||||
|
|
||||||
|
def update_gizmo_matrix(self, context):
|
||||||
|
matrix = context.object.matrix_world
|
||||||
|
self.matrix_basis.translation = matrix @ Vector((self.generate_co_data()[1]))
|
||||||
|
|
||||||
|
def update_header_text(self, context):
|
||||||
|
text = self.translate_header_text('Angle', round(math.degrees(self.modifier_angle), 3))
|
||||||
|
context.area.header_text_set(text)
|
||||||
|
|
||||||
|
|
||||||
|
class AngleGizmoGroup(GizmoGroup, GizmoUtils, Handler):
|
||||||
|
"""ShowGizmo
|
||||||
|
"""
|
||||||
|
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup'
|
||||||
|
bl_label = 'AngleGizmoGroup'
|
||||||
|
bl_space_type = 'VIEW_3D'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_options = {'3D', 'PERSISTENT', }
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return cls.simple_deform_show_gizmo_poll(context)
|
||||||
|
|
||||||
|
def setup(self, context):
|
||||||
|
sd_name = AngleGizmo.bl_idname
|
||||||
|
|
||||||
|
add_data = [
|
||||||
|
('angle',
|
||||||
|
sd_name,
|
||||||
|
{'draw_type': 'SimpleDeform_GizmoGroup_',
|
||||||
|
'color': (1.0, 0.5, 1.0),
|
||||||
|
'alpha': 0.3,
|
||||||
|
'color_highlight': (1.0, 1.0, 1.0),
|
||||||
|
'alpha_highlight': 0.3,
|
||||||
|
'use_draw_modal': True,
|
||||||
|
'scale_basis': 0.1,
|
||||||
|
'use_draw_value': True,
|
||||||
|
'mouse_dpi': 100,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.generate_gizmo_mode(add_data)
|
||||||
|
|
||||||
|
data_path = 'object.modifiers.active.deform_axis'
|
||||||
|
set_enum = 'wm.context_set_enum'
|
||||||
|
|
||||||
|
for axis in ('X', 'Y', 'Z'):
|
||||||
|
# show toggle axis button
|
||||||
|
gizmo = self.gizmos.new('GIZMO_GT_button_2d')
|
||||||
|
gizmo.icon = f'EVENT_{axis.upper()}'
|
||||||
|
gizmo.draw_options = {'BACKDROP', 'HELPLINE'}
|
||||||
|
ops = gizmo.target_set_operator(set_enum)
|
||||||
|
ops.data_path = data_path
|
||||||
|
ops.value = axis
|
||||||
|
gizmo.color = (0, 0, 0)
|
||||||
|
gizmo.alpha = 0.3
|
||||||
|
gizmo.color_highlight = 1.0, 1.0, 1.0
|
||||||
|
gizmo.alpha_highlight = 0.3
|
||||||
|
gizmo.use_draw_modal = True
|
||||||
|
gizmo.use_draw_value = True
|
||||||
|
gizmo.scale_basis = 0.1
|
||||||
|
setattr(self, f'deform_axis_{axis.lower()}', gizmo)
|
||||||
|
|
||||||
|
def refresh(self, context):
|
||||||
|
|
||||||
|
self.angle.target_set_prop('angle',
|
||||||
|
context.object.modifiers.active,
|
||||||
|
'angle')
|
||||||
|
|
||||||
|
# pro = context.object.SimpleDeformGizmo_PropertyGroup
|
||||||
|
# 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')
|
||||||
|
|
||||||
|
def draw_prepare(self, context):
|
||||||
|
ob = context.object
|
||||||
|
mat = ob.matrix_world
|
||||||
|
|
||||||
|
if 'co' in self.G_SimpleDeformGizmoHandlerDit:
|
||||||
|
def _mat(f):
|
||||||
|
co = self.G_SimpleDeformGizmoHandlerDit['co'][0]
|
||||||
|
co = (co[0] + (max(ob.dimensions) * f), co[1],
|
||||||
|
co[2] - (min(ob.dimensions) * 0.3))
|
||||||
|
return mat @ Vector(co)
|
||||||
|
|
||||||
|
self.deform_axis_x.matrix_basis.translation = _mat(0)
|
||||||
|
self.deform_axis_y.matrix_basis.translation = _mat(0.3)
|
||||||
|
self.deform_axis_z.matrix_basis.translation = _mat(0.6)
|
@ -1,13 +1,46 @@
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
from bpy.types import GizmoGroup
|
from bpy.types import GizmoGroup
|
||||||
|
from bpy_types import Gizmo
|
||||||
from mathutils import Euler, Vector
|
from mathutils import Euler, Vector
|
||||||
|
|
||||||
from ..draw import Handler
|
from ..draw import Handler
|
||||||
from ..utils import PublicUtils
|
from ..utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo(GizmoGroup, PublicUtils, Handler):
|
class CustomGizmo(Gizmo, GizmoUtils, Handler):
|
||||||
|
"""绘制自定义Gizmo"""
|
||||||
|
bl_idname = '_Custom_Gizmo'
|
||||||
|
draw_type: str
|
||||||
|
custom_shape: dict
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.draw_type = 'None_GizmoGroup_'
|
||||||
|
if not hasattr(self, 'custom_shape'):
|
||||||
|
self.custom_shape = {}
|
||||||
|
for i in self.G_GizmoCustomShapeDict:
|
||||||
|
self.custom_shape[i] = self.new_custom_shape(
|
||||||
|
'TRIS', self.G_GizmoCustomShapeDict[i])
|
||||||
|
self.add_handler()
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||||
|
|
||||||
|
def draw_select(self, context, select_id):
|
||||||
|
self.draw_custom_shape(
|
||||||
|
self.custom_shape[self.draw_type], select_id=select_id)
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def modal(self, context, event, tweak):
|
||||||
|
self.add_handler()
|
||||||
|
self.update_bound_box(context.object)
|
||||||
|
self.update_empty_matrix()
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo(GizmoGroup, GizmoUtils):
|
||||||
"""绘制切换变型轴的
|
"""绘制切换变型轴的
|
||||||
变换方向
|
变换方向
|
||||||
"""
|
"""
|
||||||
@ -23,21 +56,15 @@ class SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo(GizmoGroup, PublicUtils, H
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
pref = cls.pref_()
|
return cls.simple_deform_show_bend_axis_witch_poll(context)
|
||||||
simple = cls.simple_deform_public_poll(context)
|
|
||||||
bend = simple and (
|
|
||||||
context.object.modifiers.active.deform_method == 'BEND')
|
|
||||||
switch_axis = pref.display_bend_axis_switch_gizmo
|
|
||||||
return switch_axis and bend
|
|
||||||
|
|
||||||
def setup(self, context):
|
def setup(self, context):
|
||||||
_draw_type = 'SimpleDeform_Bend_Direction_'
|
_draw_type = 'SimpleDeform_Bend_Direction_'
|
||||||
_color_a = 1, 0, 0
|
_color_a = 1, 0, 0
|
||||||
_color_b = 0, 1, 0
|
_color_b = 0, 1, 0
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
for na, axis, rot, positive in (
|
for na, axis, rot, positive in (
|
||||||
('top_a', 'X', (math.radians(90), 0, math.radians(90)), True),
|
('top_a', 'X', (math.radians(90), 0, math.radians(9 - 0)), True),
|
||||||
('top_b', 'X', (math.radians(90), 0, 0), True),
|
('top_b', 'X', (math.radians(90), 0, 0), True),
|
||||||
|
|
||||||
('bottom_a', 'X', (math.radians(90), 0, math.radians(90)), False),
|
('bottom_a', 'X', (math.radians(90), 0, math.radians(90)), False),
|
||||||
@ -102,6 +129,5 @@ class SimpleDeformGizmoGroupDisplayBendAxiSwitchGizmo(GizmoGroup, PublicUtils, H
|
|||||||
for i, j, w, in for_list:
|
for i, j, w, in for_list:
|
||||||
gizmo = getattr(self, i, False)
|
gizmo = getattr(self, i, False)
|
||||||
rot = Euler(w, 'XYZ').to_matrix().to_4x4()
|
rot = Euler(w, 'XYZ').to_matrix().to_4x4()
|
||||||
|
|
||||||
gizmo.matrix_basis = mat.to_euler().to_matrix().to_4x4() @ rot
|
gizmo.matrix_basis = mat.to_euler().to_matrix().to_4x4() @ rot
|
||||||
gizmo.matrix_basis.translation = Vector(j)
|
gizmo.matrix_basis.translation = Vector(j)
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
from bpy.types import (
|
|
||||||
GizmoGroup,
|
|
||||||
)
|
|
||||||
from mathutils import Vector
|
|
||||||
|
|
||||||
from utils import PublicUtils
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleDeformGizmoGroup(GizmoGroup, PublicUtils):
|
|
||||||
"""显示Gizmo
|
|
||||||
"""
|
|
||||||
bl_idname = 'OBJECT_GGT_SimpleDeformGizmoGroup'
|
|
||||||
bl_label = 'SimpleDeformGizmoGroup'
|
|
||||||
bl_space_type = 'VIEW_3D'
|
|
||||||
bl_region_type = 'WINDOW'
|
|
||||||
bl_options = {'3D', 'PERSISTENT', }
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
pol = cls.simple_deform_public_poll(context)
|
|
||||||
pref = cls.pref_()
|
|
||||||
deform_method = (
|
|
||||||
pol and (context.object.modifiers.active.deform_method != 'BEND'))
|
|
||||||
display_gizmo = pref.display_bend_axis_switch_gizmo
|
|
||||||
switch = (not display_gizmo)
|
|
||||||
return pol and (deform_method or switch)
|
|
||||||
|
|
||||||
def setup(self, context):
|
|
||||||
sd_name = ViewSimpleDeformGizmo.bl_idname
|
|
||||||
|
|
||||||
add_data = (('up_limits',
|
|
||||||
sd_name,
|
|
||||||
{'ctrl_mode': 'up_limits',
|
|
||||||
'draw_type': 'Sphere_GizmoGroup_',
|
|
||||||
'mouse_dpi': 1000,
|
|
||||||
'color': (1.0, 0, 0),
|
|
||||||
'alpha': 0.5,
|
|
||||||
'color_highlight': (1.0, 1.0, 1.0),
|
|
||||||
'alpha_highlight': 0.3,
|
|
||||||
'use_draw_modal': True,
|
|
||||||
'scale_basis': 0.1,
|
|
||||||
'use_draw_value': True, }),
|
|
||||||
('down_limits',
|
|
||||||
sd_name,
|
|
||||||
{'ctrl_mode': 'down_limits',
|
|
||||||
'draw_type': 'Sphere_GizmoGroup_',
|
|
||||||
'mouse_dpi': 1000,
|
|
||||||
'color': (0, 1.0, 0),
|
|
||||||
'alpha': 0.5,
|
|
||||||
'color_highlight': (1.0, 1.0, 1.0),
|
|
||||||
'alpha_highlight': 0.3,
|
|
||||||
'use_draw_modal': True,
|
|
||||||
'scale_basis': 0.1,
|
|
||||||
'use_draw_value': True, }),
|
|
||||||
('angle',
|
|
||||||
sd_name,
|
|
||||||
{'ctrl_mode': 'angle',
|
|
||||||
'draw_type': 'SimpleDeform_GizmoGroup_',
|
|
||||||
'color': (1.0, 0.5, 1.0),
|
|
||||||
'alpha': 0.3,
|
|
||||||
'color_highlight': (1.0, 1.0, 1.0),
|
|
||||||
'alpha_highlight': 0.3,
|
|
||||||
'use_draw_modal': True,
|
|
||||||
'scale_basis': 0.1,
|
|
||||||
'use_draw_value': True,
|
|
||||||
'mouse_dpi': 100,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.generate_gizmo_mode(add_data)
|
|
||||||
|
|
||||||
data_path = 'object.modifiers.active.deform_axis'
|
|
||||||
set_enum = 'wm.context_set_enum'
|
|
||||||
|
|
||||||
for axis in ('X', 'Y', 'Z'):
|
|
||||||
# show toggle axis button
|
|
||||||
gizmo = self.gizmos.new('GIZMO_GT_button_2d')
|
|
||||||
gizmo.icon = f'EVENT_{axis.upper()}'
|
|
||||||
gizmo.draw_options = {'BACKDROP', 'HELPLINE'}
|
|
||||||
ops = gizmo.target_set_operator(set_enum)
|
|
||||||
ops.data_path = data_path
|
|
||||||
ops.value = axis
|
|
||||||
gizmo.color = (0, 0, 0)
|
|
||||||
gizmo.alpha = 0.3
|
|
||||||
gizmo.color_highlight = 1.0, 1.0, 1.0
|
|
||||||
gizmo.alpha_highlight = 0.3
|
|
||||||
gizmo.use_draw_modal = True
|
|
||||||
gizmo.use_draw_value = True
|
|
||||||
gizmo.scale_basis = 0.1
|
|
||||||
setattr(self, f'deform_axis_{axis.lower()}', gizmo)
|
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
def refresh(self, context):
|
|
||||||
pro = context.object.SimpleDeformGizmo_PropertyGroup
|
|
||||||
|
|
||||||
self.angle.target_set_prop('angle',
|
|
||||||
context.object.modifiers.active,
|
|
||||||
'angle')
|
|
||||||
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')
|
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
def draw_prepare(self, context):
|
|
||||||
ob = context.object
|
|
||||||
mat = ob.matrix_world
|
|
||||||
|
|
||||||
if 'co' in self.G_SimpleDeformGizmoHandlerDit:
|
|
||||||
def _mat(f):
|
|
||||||
co = self.G_SimpleDeformGizmoHandlerDit['co'][0]
|
|
||||||
co = (co[0] + (max(ob.dimensions) * f), co[1],
|
|
||||||
co[2] - (min(ob.dimensions) * 0.3))
|
|
||||||
return mat @ Vector(co)
|
|
||||||
|
|
||||||
self.deform_axis_x.matrix_basis.translation = _mat(0)
|
|
||||||
self.deform_axis_y.matrix_basis.translation = _mat(0.3)
|
|
||||||
self.deform_axis_z.matrix_basis.translation = _mat(0.6)
|
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
def invoke_prepare(self, context, gizmo):
|
|
||||||
self.add_handler()
|
|
@ -1,7 +1,16 @@
|
|||||||
|
import math
|
||||||
|
from typing import Callable, Any
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
from bpy_extras import view3d_utils
|
||||||
|
from bpy.types import Gizmo
|
||||||
|
from mathutils import Euler, Vector
|
||||||
|
|
||||||
|
from ..draw import Handler
|
||||||
|
from ..utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class GizmoProperty(Gizmo, PublicUtils, Handler):
|
class GizmoProperty(GizmoUtils, Handler):
|
||||||
@property
|
@property
|
||||||
def is_angle_mode(self):
|
def is_angle_mode(self):
|
||||||
return self.ctrl_mode == 'angle'
|
return self.ctrl_mode == 'angle'
|
||||||
@ -15,15 +24,14 @@ class GizmoProperty(Gizmo, PublicUtils, Handler):
|
|||||||
return self.ctrl_mode == 'down_limits'
|
return self.ctrl_mode == 'down_limits'
|
||||||
|
|
||||||
|
|
||||||
class ViewSimpleDeformGizmo(GizmoProperty):
|
class UpDownLimitsGizmo(GizmoProperty, Gizmo):
|
||||||
"""显示轴向切换拖动点Gizmo(两个点)
|
"""显示轴向切换拖动点Gizmo(两个点)
|
||||||
"""
|
"""
|
||||||
bl_idname = 'ViewSimpleDeformGizmo'
|
bl_idname = '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},
|
||||||
{'id': 'angle', 'type': 'FLOAT', 'array_length': 1},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
@ -46,27 +54,6 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
'rotate_follow_modifier',
|
'rotate_follow_modifier',
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_gizmo_rotate(self, axis, mod):
|
|
||||||
if self.rotate_follow_modifier:
|
|
||||||
rot = Euler()
|
|
||||||
if axis == 'X' and (not self.is_positive(mod.angle)):
|
|
||||||
rot.z = math.pi
|
|
||||||
|
|
||||||
elif axis == 'Y':
|
|
||||||
if self.is_positive(mod.angle):
|
|
||||||
rot.z = -(math.pi / 2)
|
|
||||||
else:
|
|
||||||
rot.z = math.pi / 2
|
|
||||||
elif axis == 'Z':
|
|
||||||
if self.is_positive(mod.angle):
|
|
||||||
rot.x = rot.z = rot.y = math.pi / 2
|
|
||||||
else:
|
|
||||||
rot.z = rot.y = math.pi / 2
|
|
||||||
rot.x = -(math.pi / 2)
|
|
||||||
|
|
||||||
rot = rot.to_matrix()
|
|
||||||
self.matrix_basis = self.matrix_basis @ rot.to_4x4()
|
|
||||||
|
|
||||||
def update_draw_limits_bound_box(self, data, mod, axis, mat, up_, down_):
|
def update_draw_limits_bound_box(self, data, mod, axis, mat, up_, down_):
|
||||||
top, bottom, left, right, front, back = data
|
top, bottom, left, right, front, back = data
|
||||||
if mod.origin:
|
if mod.origin:
|
||||||
@ -111,7 +98,6 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
self.matrix_basis = ob.matrix_world.normalized()
|
self.matrix_basis = ob.matrix_world.normalized()
|
||||||
|
|
||||||
co = self.generate_co_data()
|
co = self.generate_co_data()
|
||||||
self.update_gizmo_rotate(axis, mod)
|
|
||||||
# calculation limits position
|
# calculation limits position
|
||||||
top, bottom, left, right, front, back = self.each_face_pos(mat)
|
top, bottom, left, right, front, back = self.each_face_pos(mat)
|
||||||
(up, down), (up_, down_) = self.get_limits_pos(
|
(up, down), (up_, down_) = self.get_limits_pos(
|
||||||
@ -130,38 +116,19 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
def setup(self):
|
def setup(self):
|
||||||
self.generate_co_data()
|
self.generate_co_data()
|
||||||
self.draw_type = 'None_GizmoGroup_'
|
self.draw_type = 'None_GizmoGroup_'
|
||||||
self.ctrl_mode = 'angle' # up_limits , down_limits
|
self.ctrl_mode = 'up_limits' # up_limits , down_limits
|
||||||
self.mouse_dpi = 10
|
self.mouse_dpi = 10
|
||||||
self.rotate_follow_modifier = True
|
self.rotate_follow_modifier = True
|
||||||
if not hasattr(self, 'custom_shape'):
|
|
||||||
self.custom_shape = {}
|
|
||||||
for i in self.G_GizmoCustomShapeDict:
|
|
||||||
item = self.G_GizmoCustomShapeDict[i]
|
|
||||||
self.custom_shape[i] = self.new_custom_shape('TRIS', item)
|
|
||||||
self.add_handler()
|
self.add_handler()
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
self.add_handler()
|
|
||||||
|
|
||||||
self.update_gizmo_matrix(context)
|
|
||||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
|
||||||
|
|
||||||
def draw_select(self, context, select_id):
|
|
||||||
self.update_gizmo_matrix(context)
|
|
||||||
self.draw_custom_shape(
|
|
||||||
self.custom_shape[self.draw_type], select_id=select_id)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
self.init_mouse_y = event.mouse_y
|
self.init_invoke(context, event)
|
||||||
self.init_mouse_x = event.mouse_x
|
|
||||||
mod = context.object.modifiers.active
|
mod = context.object.modifiers.active
|
||||||
limits = mod.limits
|
limits = mod.limits
|
||||||
up_limits = limits[1]
|
up_limits = limits[1]
|
||||||
down_limits = limits[0]
|
down_limits = limits[0]
|
||||||
|
|
||||||
if 'angle' == self.ctrl_mode:
|
if 'up_limits' == self.ctrl_mode:
|
||||||
self.int_value_angle = self.target_get_value('angle')
|
|
||||||
elif 'up_limits' == self.ctrl_mode:
|
|
||||||
self.int_value_up_limits = up_limits
|
self.int_value_up_limits = up_limits
|
||||||
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 'down_limits' == self.ctrl_mode:
|
||||||
@ -179,7 +146,6 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
self.target_set_value('deform_axis', self.value_deform_axis)
|
self.target_set_value('deform_axis', self.value_deform_axis)
|
||||||
elif 'up_limits' == self.ctrl_mode:
|
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 'down_limits' == self.ctrl_mode:
|
||||||
self.target_set_value(
|
self.target_set_value(
|
||||||
'down_limits', self.int_value_down_limits)
|
'down_limits', self.int_value_down_limits)
|
||||||
@ -256,14 +222,6 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
elif self.is_down_limits_mode:
|
elif self.is_down_limits_mode:
|
||||||
self.set_down_value(data, mu)
|
self.set_down_value(data, mu)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def snap_value(value, event: 'bpy.types.Event'):
|
|
||||||
if event.ctrl:
|
|
||||||
value //= 5
|
|
||||||
elif event.ctrl and event.shift:
|
|
||||||
value //= 1
|
|
||||||
return value
|
|
||||||
|
|
||||||
def update_header_text(self, context, mod, origin, up_limits, down_limits):
|
def update_header_text(self, context, mod, origin, up_limits, down_limits):
|
||||||
translate: Callable[[Any], str] = lambda t: bpy.app.translations.pgettext(t)
|
translate: Callable[[Any], str] = lambda t: bpy.app.translations.pgettext(t)
|
||||||
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
|
||||||
@ -274,7 +232,7 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
text = translate(mode) + ' '
|
text = translate(mode) + ' '
|
||||||
|
|
||||||
if self.is_use_angle_value and self.is_angle_mode:
|
if self.is_use_angle_value and self.is_angle_mode:
|
||||||
text += t_('Angle', math.degrees(mod.angle))
|
text += t_()
|
||||||
elif self.is_up_limits_mode:
|
elif self.is_up_limits_mode:
|
||||||
text += t_('Upper limit', up_limits)
|
text += t_('Upper limit', up_limits)
|
||||||
elif self.is_down_limits_mode:
|
elif self.is_down_limits_mode:
|
||||||
@ -306,7 +264,6 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
def modal(self, context, event, tweak):
|
def modal(self, context, event, tweak):
|
||||||
self.update_bound_box(context.object)
|
self.update_bound_box(context.object)
|
||||||
|
|
||||||
delta = (self.init_mouse_x - event.mouse_x) / self.mouse_dpi
|
|
||||||
ob = context.object
|
ob = context.object
|
||||||
mod = ob.modifiers.active
|
mod = ob.modifiers.active
|
||||||
limits = mod.limits
|
limits = mod.limits
|
||||||
@ -320,10 +277,7 @@ class ViewSimpleDeformGizmo(GizmoProperty):
|
|||||||
min_value = down_limits + limit_scope
|
min_value = down_limits + limit_scope
|
||||||
difference_value = up_limits - down_limits
|
difference_value = up_limits - down_limits
|
||||||
|
|
||||||
if 'SNAP' in tweak:
|
delta = self.get_delta(event, tweak)
|
||||||
delta = round(delta)
|
|
||||||
if 'PRECISE' in tweak:
|
|
||||||
delta /= self.mouse_dpi
|
|
||||||
delta = self.delta_update(context, event, delta)
|
delta = self.delta_update(context, event, delta)
|
||||||
|
|
||||||
if origin_mode != 'NOT' and ('draw_line' in self.G_SimpleDeformGizmoHandlerDit):
|
if origin_mode != 'NOT' and ('draw_line' in self.G_SimpleDeformGizmoHandlerDit):
|
@ -4,10 +4,10 @@ import bpy
|
|||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy.props import FloatProperty, StringProperty, BoolProperty
|
from bpy.props import FloatProperty, StringProperty, BoolProperty
|
||||||
|
|
||||||
from .utils import PublicUtils
|
from .utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class DeformAxisOperator(Operator, PublicUtils):
|
class DeformAxisOperator(Operator, GizmoUtils):
|
||||||
bl_idname = 'simple_deform_gizmo.deform_axis'
|
bl_idname = 'simple_deform_gizmo.deform_axis'
|
||||||
bl_label = 'deform_axis'
|
bl_label = 'deform_axis'
|
||||||
bl_description = 'deform_axis operator'
|
bl_description = 'deform_axis operator'
|
||||||
@ -26,12 +26,12 @@ class DeformAxisOperator(Operator, PublicUtils):
|
|||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
def modal(self, context, event):
|
def modal(self, context, event):
|
||||||
from gizmo.ctrl_value_and_factor import PublicUtils
|
from gizmo.angle_and_factor import 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 = PublicUtils.new_empty(context.object, mod)
|
empty, con_limit_name = GizmoUtils.new_empty(context.object, mod)
|
||||||
is_positive = PublicUtils.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),
|
||||||
('min_x', self.X_Value),
|
('min_x', self.X_Value),
|
||||||
@ -48,7 +48,7 @@ class DeformAxisOperator(Operator, PublicUtils):
|
|||||||
if not event.ctrl:
|
if not event.ctrl:
|
||||||
self.pref.display_bend_axis_switch_gizmo = False
|
self.pref.display_bend_axis_switch_gizmo = False
|
||||||
|
|
||||||
PublicUtils.update_bound_box(context.object)
|
GizmoUtils.update_bound_box(context.object)
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Panel, VIEW3D_HT_tool_header
|
from bpy.types import Panel, VIEW3D_HT_tool_header
|
||||||
|
|
||||||
from .utils import PublicUtils
|
from .utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class SimpleDeformHelperToolPanel(Panel, PublicUtils):
|
class SimpleDeformHelperToolPanel(Panel, GizmoUtils):
|
||||||
bl_space_type = 'VIEW_3D'
|
bl_space_type = 'VIEW_3D'
|
||||||
bl_region_type = 'UI'
|
bl_region_type = 'UI'
|
||||||
bl_category = 'Tool'
|
bl_category = 'Tool'
|
||||||
@ -16,7 +16,7 @@ class SimpleDeformHelperToolPanel(Panel, PublicUtils):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return PublicUtils.simple_deform_public_poll(context)
|
return cls.simple_deform_public_poll(context)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
cls = SimpleDeformHelperToolPanel
|
cls = SimpleDeformHelperToolPanel
|
||||||
|
@ -11,11 +11,11 @@ from bpy.types import (
|
|||||||
PropertyGroup,
|
PropertyGroup,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .utils import PublicUtils, GizmoUtils
|
from .utils import GizmoUtils
|
||||||
|
|
||||||
|
|
||||||
class SimpleDeformGizmoAddonPreferences(AddonPreferences, PublicUtils):
|
class SimpleDeformGizmoAddonPreferences(AddonPreferences, GizmoUtils):
|
||||||
bl_idname = PublicUtils.G_ADDON_NAME
|
bl_idname = GizmoUtils.G_ADDON_NAME
|
||||||
|
|
||||||
deform_wireframe_color: FloatVectorProperty(
|
deform_wireframe_color: FloatVectorProperty(
|
||||||
name='Deform Wireframe',
|
name='Deform Wireframe',
|
||||||
@ -141,7 +141,7 @@ register_class, unregister_class = bpy.utils.register_classes_factory(class_list
|
|||||||
def register():
|
def register():
|
||||||
register_class()
|
register_class()
|
||||||
|
|
||||||
PublicUtils.pref_().display_bend_axis_switch_gizmo = False
|
GizmoUtils.pref_().display_bend_axis_switch_gizmo = False
|
||||||
bpy.types.Object.SimpleDeformGizmo_PropertyGroup = PointerProperty(
|
bpy.types.Object.SimpleDeformGizmo_PropertyGroup = PointerProperty(
|
||||||
type=SimpleDeformGizmoObjectPropertyGroup,
|
type=SimpleDeformGizmoObjectPropertyGroup,
|
||||||
name='SimpleDeformGizmo_PropertyGroup')
|
name='SimpleDeformGizmo_PropertyGroup')
|
||||||
|
@ -8,7 +8,7 @@ from typing import Callable, Any
|
|||||||
import bpy
|
import bpy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from bpy.types import AddonPreferences
|
from bpy.types import AddonPreferences
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix, Euler
|
||||||
|
|
||||||
|
|
||||||
class PublicData:
|
class PublicData:
|
||||||
@ -93,7 +93,61 @@ class PublicClass(PublicData):
|
|||||||
return PublicClass.pref_()
|
return PublicClass.pref_()
|
||||||
|
|
||||||
|
|
||||||
class PublicUtils(PublicClass):
|
class PublicPoll(PublicClass):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def simple_deform_public_poll(cls, context: 'bpy.types.context') -> bool:
|
||||||
|
"""Public poll
|
||||||
|
In 3D View
|
||||||
|
Active Object in ('MESH', 'LATTICE')
|
||||||
|
Active Modifier Type Is 'SIMPLE_DEFORM' and show_viewport
|
||||||
|
return True
|
||||||
|
"""
|
||||||
|
obj = context.object
|
||||||
|
if not obj:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mod = obj.modifiers.active
|
||||||
|
if not mod:
|
||||||
|
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_modifiers_type = mod and (mod.type == 'SIMPLE_DEFORM')
|
||||||
|
is_available_obj = available_modifiers_type and available_obj_type
|
||||||
|
is_obj_mode = context.mode == 'OBJECT'
|
||||||
|
show_mod = mod.show_viewport
|
||||||
|
return is_available_obj and is_obj_mode and show_gizmo and show_mod
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _simple_deform_modifier_is_bend_poll(cls, context):
|
||||||
|
"""
|
||||||
|
Public poll
|
||||||
|
active modifier deform_method =='BEND'
|
||||||
|
"""
|
||||||
|
simple = cls.simple_deform_public_poll(context)
|
||||||
|
is_bend = (context.object.modifiers.active.deform_method == 'BEND')
|
||||||
|
return simple and is_bend
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def simple_deform_show_bend_axis_witch_poll(cls, context):
|
||||||
|
"""
|
||||||
|
Show D
|
||||||
|
"""
|
||||||
|
switch_axis = cls.pref_().display_bend_axis_switch_gizmo
|
||||||
|
bend = cls._simple_deform_modifier_is_bend_poll(context)
|
||||||
|
return switch_axis and bend
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def simple_deform_show_gizmo_poll(cls, context):
|
||||||
|
poll = cls.simple_deform_public_poll(context)
|
||||||
|
not_switch = (not cls.simple_deform_show_bend_axis_witch_poll(context))
|
||||||
|
return poll and not_switch
|
||||||
|
|
||||||
|
|
||||||
|
class PublicUtils(PublicPoll):
|
||||||
@classmethod
|
@classmethod
|
||||||
def value_limit(cls, value, max_value=1, min_value=0):
|
def value_limit(cls, value, max_value=1, min_value=0):
|
||||||
"""
|
"""
|
||||||
@ -154,7 +208,7 @@ class PublicUtils(PublicClass):
|
|||||||
return tuple(i[:] for i in obj.bound_box)
|
return tuple(i[:] for i in obj.bound_box)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_mesh_max_min_co(cls, obj: 'bpy.context.object') -> tuple:
|
def get_mesh_max_min_co(cls, obj: 'bpy.context.object') -> '[Vector,Vector]':
|
||||||
if obj.type == 'MESH':
|
if obj.type == 'MESH':
|
||||||
ver_len = obj.data.vertices.__len__()
|
ver_len = obj.data.vertices.__len__()
|
||||||
list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
|
list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
|
||||||
@ -165,7 +219,7 @@ class PublicUtils(PublicClass):
|
|||||||
list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
|
list_vertices = np.zeros(ver_len * 3, dtype=np.float32)
|
||||||
obj.data.points.foreach_get('co', list_vertices)
|
obj.data.points.foreach_get('co', list_vertices)
|
||||||
list_vertices = list_vertices.reshape(ver_len, 3)
|
list_vertices = list_vertices.reshape(ver_len, 3)
|
||||||
return tuple(list_vertices.min(axis=0)), tuple(list_vertices.max(axis=0))
|
return Vector(list_vertices.min(axis=0)), Vector(list_vertices.max(axis=0))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def matrix_calculation(cls, mat: 'Matrix', calculation_list: 'list') -> list:
|
def matrix_calculation(cls, mat: 'Matrix', calculation_list: 'list') -> list:
|
||||||
@ -203,9 +257,51 @@ class PublicUtils(PublicClass):
|
|||||||
(d, b)
|
(d, b)
|
||||||
(c, a)))
|
(c, a)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def translate_text(cls, text):
|
||||||
|
return bpy.app.translations.pgettext(text)
|
||||||
|
|
||||||
class GizmoUtils(PublicUtils):
|
@classmethod
|
||||||
|
def translate_header_text(cls, mode, value):
|
||||||
|
return cls.translate_text(mode) + ':{}'.format(value)
|
||||||
|
|
||||||
|
|
||||||
|
class GizmoProperty:
|
||||||
|
|
||||||
|
@property
|
||||||
|
def obj(self):
|
||||||
|
return bpy.context.object
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier(self):
|
||||||
|
obj = self.obj
|
||||||
|
if not obj:
|
||||||
|
return
|
||||||
|
return obj.modifiers.active
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_deform_axis(self):
|
||||||
|
mod = self.modifier
|
||||||
|
if mod:
|
||||||
|
return mod.deform_axis
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modifier_angle(self):
|
||||||
|
mod = self.modifier
|
||||||
|
if mod:
|
||||||
|
return mod.angle
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_modifier_is_simple_deform(self):
|
||||||
|
return self.modifier and self.modifier.type == 'SIMPLE_DEFORM'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_use_angle_value(self):
|
||||||
|
if self.active_modifier_is_simple_deform:
|
||||||
|
return self.modifier.deform_method in ('TWIST', 'BEND')
|
||||||
|
|
||||||
|
|
||||||
|
class GizmoClassMethod(GizmoProperty, PublicUtils):
|
||||||
@classmethod
|
@classmethod
|
||||||
def each_face_pos(cls, mat: 'Matrix' = None):
|
def each_face_pos(cls, mat: 'Matrix' = None):
|
||||||
if mat is None:
|
if mat is None:
|
||||||
@ -245,32 +341,6 @@ class GizmoUtils(PublicUtils):
|
|||||||
else:
|
else:
|
||||||
return ob.SimpleDeformGizmo_PropertyGroup
|
return ob.SimpleDeformGizmo_PropertyGroup
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def simple_deform_public_poll(cls, context: 'bpy.types.context') -> bool:
|
|
||||||
"""Public poll
|
|
||||||
In 3D View
|
|
||||||
Active Object in ('MESH', 'LATTICE')
|
|
||||||
Active Modifier Type Is 'SIMPLE_DEFORM' and show_viewport
|
|
||||||
return True
|
|
||||||
"""
|
|
||||||
obj = context.object
|
|
||||||
if not obj:
|
|
||||||
return False
|
|
||||||
|
|
||||||
mod = obj.modifiers.active
|
|
||||||
if not mod:
|
|
||||||
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_modifiers_type = mod and (mod.type == 'SIMPLE_DEFORM')
|
|
||||||
is_available_obj = available_modifiers_type and available_obj_type
|
|
||||||
is_obj_mode = context.mode == 'OBJECT'
|
|
||||||
show_mod = mod.show_viewport
|
|
||||||
return is_available_obj and is_obj_mode and show_gizmo and show_mod
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_up_down_return_list(cls, mod, axis, up_, down_, data):
|
def get_up_down_return_list(cls, mod, axis, up_, down_, data):
|
||||||
top, bottom, left, right, front, back = data
|
top, bottom, left, right, front, back = data
|
||||||
@ -418,7 +488,7 @@ class GizmoUtils(PublicUtils):
|
|||||||
matrix = obj.matrix_world.copy() # 物体矩阵
|
matrix = obj.matrix_world.copy() # 物体矩阵
|
||||||
# add simple_deform mesh
|
# add simple_deform mesh
|
||||||
(min_x, min_y, min_z), (max_x, max_y,
|
(min_x, min_y, min_z), (max_x, max_y,
|
||||||
max_z) = cls.get_mesh_max_min_co(object)
|
max_z) = cls.get_mesh_max_min_co(obj)
|
||||||
vertexes = ((max_x, min_y, min_z),
|
vertexes = ((max_x, min_y, min_z),
|
||||||
(min_x, min_y, min_z),
|
(min_x, min_y, min_z),
|
||||||
(max_x, max_y, min_z),
|
(max_x, max_y, min_z),
|
||||||
@ -526,7 +596,85 @@ class GizmoUtils(PublicUtils):
|
|||||||
modifiers_co['co']
|
modifiers_co['co']
|
||||||
|
|
||||||
|
|
||||||
class tmp:
|
class GizmoUtils(GizmoClassMethod):
|
||||||
|
custom_shape: dict
|
||||||
|
init_mouse_y: float
|
||||||
|
init_mouse_x: float
|
||||||
|
mouse_dpi: int
|
||||||
|
matrix_basis: Matrix
|
||||||
|
draw_type: str
|
||||||
|
|
||||||
|
def generate_gizmo_mode(self, gizmo_data):
|
||||||
|
"""生成gizmo的上限下限及角度设置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gizmo_data (_type_): _description_
|
||||||
|
"""
|
||||||
|
for i, j, k in gizmo_data:
|
||||||
|
setattr(self, i, self.gizmos.new(j))
|
||||||
|
gizmo = getattr(self, i)
|
||||||
|
for f in k:
|
||||||
|
if f == 'target_set_operator':
|
||||||
|
gizmo.target_set_operator(k[f])
|
||||||
|
elif f == 'target_set_prop':
|
||||||
|
gizmo.target_set_prop(*k[f])
|
||||||
|
else:
|
||||||
|
setattr(gizmo, f, k[f])
|
||||||
|
|
||||||
|
def init_shape(self):
|
||||||
|
if not hasattr(self, 'custom_shape'):
|
||||||
|
self.custom_shape = {}
|
||||||
|
for i in self.G_GizmoCustomShapeDict:
|
||||||
|
item = self.G_GizmoCustomShapeDict[i]
|
||||||
|
self.custom_shape[i] = self.new_custom_shape('TRIS', item)
|
||||||
|
|
||||||
|
def init_setup(self):
|
||||||
|
self.init_shape()
|
||||||
|
|
||||||
|
def init_invoke(self, context, event):
|
||||||
|
self.init_mouse_y = event.mouse_y
|
||||||
|
self.init_mouse_x = event.mouse_x
|
||||||
|
|
||||||
|
def _update_matrix(self, context):
|
||||||
|
func = getattr(self, 'update_gizmo_matrix', None)
|
||||||
|
if func:
|
||||||
|
func(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||||
|
self._update_matrix(context)
|
||||||
|
|
||||||
|
def draw_select(self, context, select_id):
|
||||||
|
self.draw_custom_shape(
|
||||||
|
self.custom_shape[self.draw_type], select_id=select_id)
|
||||||
|
self._update_matrix(context)
|
||||||
|
|
||||||
|
def get_delta(self, event):
|
||||||
|
delta = (self.init_mouse_x - event.mouse_x) / self.mouse_dpi
|
||||||
|
return delta
|
||||||
|
|
||||||
|
def get_snap(self, delta, tweak):
|
||||||
|
# ctrl SNAP
|
||||||
|
# shift PRECISE
|
||||||
|
is_snap = 'SNAP' in tweak
|
||||||
|
is_precise = 'PRECISE' in tweak
|
||||||
|
if is_snap and is_precise:
|
||||||
|
delta = round(delta)
|
||||||
|
# delta /= self.mouse_dpi
|
||||||
|
elif is_snap:
|
||||||
|
delta //= 5
|
||||||
|
delta *= 5
|
||||||
|
elif is_precise:
|
||||||
|
delta //= 0.01
|
||||||
|
delta *= 0.01
|
||||||
|
print('tweak', delta, tweak)
|
||||||
|
return delta
|
||||||
|
|
||||||
|
def update_gizmo_matrix(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Tmp:
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_origin_bounds(cls, obj: 'bpy.types.Object') -> list:
|
def get_origin_bounds(cls, obj: 'bpy.types.Object') -> list:
|
||||||
modifiers_dict = {}
|
modifiers_dict = {}
|
||||||
@ -546,6 +694,29 @@ class tmp:
|
|||||||
mod.show_viewport = show_viewport
|
mod.show_viewport = show_viewport
|
||||||
return list(bound)
|
return list(bound)
|
||||||
|
|
||||||
|
def update_gizmo_rotate(self):
|
||||||
|
mod = self.modifier
|
||||||
|
axis = self.modifier_deform_axis
|
||||||
|
if self.rotate_follow_modifier:
|
||||||
|
rot = Euler()
|
||||||
|
if axis == 'X' and (not self.is_positive(mod.angle)):
|
||||||
|
rot.z = math.pi
|
||||||
|
|
||||||
|
elif axis == 'Y':
|
||||||
|
if self.is_positive(mod.angle):
|
||||||
|
rot.z = -(math.pi / 2)
|
||||||
|
else:
|
||||||
|
rot.z = math.pi / 2
|
||||||
|
elif axis == 'Z':
|
||||||
|
if self.is_positive(mod.angle):
|
||||||
|
rot.x = rot.z = rot.y = math.pi / 2
|
||||||
|
else:
|
||||||
|
rot.z = rot.y = math.pi / 2
|
||||||
|
rot.x = -(math.pi / 2)
|
||||||
|
|
||||||
|
rot = rot.to_matrix()
|
||||||
|
self.matrix_basis = self.matrix_basis @ rot.to_4x4()
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
PublicData.load_gizmo_data()
|
PublicData.load_gizmo_data()
|
||||||
|
Loading…
Reference in New Issue
Block a user