new addon simple_deform_helper #104464
@ -5,22 +5,23 @@ import gpu
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from mathutils import Vector
|
||||
|
||||
from .update import change_active_object, simple_update
|
||||
from .utils import GizmoUtils
|
||||
|
||||
|
||||
class Handler:
|
||||
@classmethod
|
||||
def add_handler(cls):
|
||||
if 'handler' not in cls.G_GizmoData:
|
||||
cls.G_GizmoData['handler'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||
if 'handler' not in cls.G_HandleData:
|
||||
cls.G_HandleData['handler'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||
Draw3D().draw, (), 'WINDOW', 'POST_VIEW')
|
||||
|
||||
@classmethod
|
||||
def del_handler_text(cls):
|
||||
if 'scale_text' in cls.G_GizmoData:
|
||||
if 'scale_text' in cls.G_HandleData:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(
|
||||
cls.G_GizmoData['scale_text'], 'WINDOW')
|
||||
cls.G_GizmoData.pop('scale_text')
|
||||
cls.G_HandleData['scale_text'], 'WINDOW')
|
||||
cls.G_HandleData.pop('scale_text')
|
||||
|
||||
@classmethod
|
||||
def del_handler(cls):
|
||||
@ -33,10 +34,10 @@ class Handler:
|
||||
|
||||
cls.del_handler_text()
|
||||
|
||||
if 'handler' in cls.G_GizmoData:
|
||||
if 'handler' in cls.G_HandleData:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(
|
||||
cls.G_GizmoData['handler'], 'WINDOW')
|
||||
cls.G_GizmoData.clear()
|
||||
cls.G_HandleData['handler'], 'WINDOW')
|
||||
cls.G_HandleData.clear()
|
||||
|
||||
|
||||
class DrawPublic:
|
||||
@ -94,12 +95,14 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
|
||||
gpu.state.depth_test_set('ALWAYS')
|
||||
|
||||
context = bpy.context
|
||||
if self.simple_deform_public_poll(context):
|
||||
if simple_update.timers_update_poll():
|
||||
is_switch_obj = change_active_object.is_change_active_object(False)
|
||||
if self.simple_deform_public_poll(context) and not is_switch_obj:
|
||||
self.draw_3d(context)
|
||||
|
||||
def draw_3d(self, context):
|
||||
self.draw_scale_text(self.obj)
|
||||
if not self.modifier_origin_angle_is_available:
|
||||
if not self.modifier_origin_is_available:
|
||||
self.draw_bound_box()
|
||||
elif self.simple_deform_show_gizmo_poll(context):
|
||||
# draw bound box
|
||||
@ -136,20 +139,21 @@ class Draw3D(GizmoUtils, DrawPublic, DrawText, Handler):
|
||||
|
||||
def draw_deform_mesh(self):
|
||||
ob = self.obj
|
||||
handler_dit = self.G_GizmoData
|
||||
deform_data = self.G_DeformDrawData
|
||||
active = self.modifier
|
||||
# draw deform mesh
|
||||
if 'simple_deform_box_data' in handler_dit and self.pref.update_deform_wireframe:
|
||||
pos, indices, mat, mod_data, limits = handler_dit['simple_deform_box_data']
|
||||
if ([getattr(active, i) for i in self.G_MODIFIERS_PROPERTY] == mod_data) and (
|
||||
ob.matrix_world == mat) and limits == active.limits[:]:
|
||||
self.draw_3d_shader(
|
||||
pos, indices, self.pref.deform_wireframe_color)
|
||||
if 'simple_deform_bound_data' in deform_data and self.pref.update_deform_wireframe:
|
||||
modifiers = self.get_modifiers_parameter(self.modifier)
|
||||
pos, indices, mat, mod_data, limits = deform_data['simple_deform_bound_data']
|
||||
is_limits = limits == active.limits[:]
|
||||
is_mat = (ob.matrix_world == mat)
|
||||
if modifiers == mod_data and is_mat and is_limits:
|
||||
self.draw_3d_shader(pos, indices, self.pref.deform_wireframe_color)
|
||||
|
||||
def draw_scale_text(self, ob):
|
||||
scale_error = (ob.scale != Vector((1, 1, 1)))
|
||||
if scale_error and ('scale_text' not in self.G_GizmoData):
|
||||
self.G_GizmoData['scale_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||
if scale_error and ('scale_text' not in self.G_HandleData):
|
||||
self.G_HandleData['scale_text'] = bpy.types.SpaceView3D.draw_handler_add(
|
||||
self.draw_str, (), 'WINDOW', 'POST_PIXEL')
|
||||
elif not scale_error:
|
||||
self.del_handler_text()
|
||||
|
@ -6,6 +6,7 @@ from bpy.types import (
|
||||
GizmoGroup,
|
||||
)
|
||||
|
||||
from ..update import change_active_modifier_parameter
|
||||
from ..utils import GizmoUtils, GizmoGroupUtils
|
||||
|
||||
|
||||
@ -109,10 +110,13 @@ class AngleGizmo(Gizmo, AngleUpdate):
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event, tweak):
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
|
||||
self.update_prop_value(event, tweak)
|
||||
self.update_deform_wireframe()
|
||||
self.update_header_text(context)
|
||||
change_active_modifier_parameter.update_modifier_parameter()
|
||||
self.tag_redraw(context)
|
||||
return self.event_handle(event)
|
||||
|
||||
def exit(self, context, cancel):
|
||||
|
@ -14,12 +14,7 @@ class CustomGizmo(Gizmo, GizmoUtils):
|
||||
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_CustomShape:
|
||||
self.custom_shape[i] = self.new_custom_shape(
|
||||
'TRIS', self.G_CustomShape[i])
|
||||
self.init_setup()
|
||||
|
||||
def draw(self, context):
|
||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||
@ -29,6 +24,7 @@ class CustomGizmo(Gizmo, GizmoUtils):
|
||||
self.custom_shape[self.draw_type], select_id=select_id)
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.init_invoke(context, event)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event, tweak):
|
||||
|
@ -34,17 +34,18 @@ class SetDeformGizmoGroup(GizmoGroup, GizmoGroupUtils):
|
||||
setattr(self, f'deform_axis_{axis.lower()}', gizmo)
|
||||
|
||||
def draw_prepare(self, context):
|
||||
|
||||
if 'co' in self.G_GizmoData:
|
||||
bound = self.modifier_bound_co
|
||||
if bound:
|
||||
obj = self.get_depsgraph(self.obj)
|
||||
dimensions = obj.dimensions
|
||||
|
||||
def _mat(f):
|
||||
co = self.G_GizmoData['co'][0]
|
||||
co = (co[0] + (max(dimensions) * f), co[1],
|
||||
co[2] - (min(dimensions) * 0.3))
|
||||
def mat(f):
|
||||
b = bound[0]
|
||||
co = (b[0] + (max(dimensions) * f),
|
||||
b[1],
|
||||
b[2] - (min(dimensions) * 0.3))
|
||||
return self.obj_matrix_world @ 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.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)
|
||||
|
@ -6,6 +6,7 @@ from bpy.types import Gizmo, GizmoGroup
|
||||
from bpy_extras import view3d_utils
|
||||
from mathutils import Vector
|
||||
|
||||
from ..update import change_active_modifier_parameter
|
||||
from ..utils import GizmoUtils, GizmoGroupUtils
|
||||
|
||||
|
||||
@ -201,22 +202,26 @@ class UpDownLimitsGizmo(Gizmo, GizmoUpdate):
|
||||
'down_limits', self.int_value_down_limits)
|
||||
|
||||
def modal(self, context, event, tweak):
|
||||
st = time()
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
|
||||
if self.modifier_is_use_origin_axis:
|
||||
self.new_origin_empty_object()
|
||||
# return {'RUNNING_MODAL'}
|
||||
|
||||
self.difference_value = self.modifier_up_limits - self.modifier_down_limits
|
||||
self.middle_limits_value = (self.modifier_up_limits + self.modifier_down_limits) / 2
|
||||
|
||||
try:
|
||||
self.set_prop_value(event)
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
self.update_object_origin_matrix()
|
||||
# self.update_deform_wireframe(self.get_depsgraph(origin_object))
|
||||
except Exception:
|
||||
...
|
||||
# return {'FINISHED'}
|
||||
self.update_header_text(context)
|
||||
return_handle = self.event_handle(event)
|
||||
print('modal time sum ', time() - st)
|
||||
change_active_modifier_parameter.update_modifier_parameter()
|
||||
self.update_deform_wireframe()
|
||||
return return_handle
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ class DeformAxisOperator(Operator, GizmoUtils):
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event):
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
mod = context.object.modifiers.active
|
||||
mod.deform_axis = self.Deform_Axis
|
||||
empty = self.new_origin_empty_object()
|
||||
@ -39,7 +39,7 @@ class DeformAxisOperator(Operator, GizmoUtils):
|
||||
('max_z', self.Z_Value),
|
||||
('min_z', self.Z_Value),
|
||||
):
|
||||
setattr(empty.constraints[self.G_CON_LIMIT_NAME], limit, value)
|
||||
setattr(empty.constraints[self.G_NAME_CON_LIMIT], limit, value)
|
||||
|
||||
if ((not is_positive) and self.Is_Positive) or (is_positive and (not self.Is_Positive)):
|
||||
mod.angle = mod.angle * -1
|
||||
|
@ -41,7 +41,7 @@ class SimpleDeformHelperToolPanel(Panel, GizmoUtils):
|
||||
'show_set_axis_button',
|
||||
icon='EMPTY_AXIS',
|
||||
text='')
|
||||
if mod.deform_method == 'BEND':
|
||||
if pref.modifier_deform_method_is_bend:
|
||||
layout.prop(pref,
|
||||
'display_bend_axis_switch_gizmo',
|
||||
toggle=1)
|
||||
|
@ -96,12 +96,10 @@ class SimpleDeformGizmoAddonPreferences(AddonPreferences, GizmoUtils):
|
||||
row.prop(mod, show_type)
|
||||
|
||||
|
||||
class SimpleDeformGizmoObjectPropertyGroup(PropertyGroup):
|
||||
class SimpleDeformGizmoObjectPropertyGroup(PropertyGroup, GizmoUtils):
|
||||
def _limits_up(self, context):
|
||||
mod = context.object.modifiers
|
||||
if mod and (mod.active.type == 'SIMPLE_DEFORM'):
|
||||
mod = mod.active
|
||||
mod.limits[1] = self.up_limits
|
||||
if self.active_modifier_is_simple_deform:
|
||||
self.modifier.limits[1] = self.up_limits
|
||||
|
||||
up_limits: FloatProperty(name='up',
|
||||
description='UP Limits(Red)',
|
||||
@ -111,10 +109,8 @@ class SimpleDeformGizmoObjectPropertyGroup(PropertyGroup):
|
||||
min=0)
|
||||
|
||||
def _limits_down(self, context):
|
||||
mod = context.object.modifiers
|
||||
if mod and (mod.active.type == 'SIMPLE_DEFORM'):
|
||||
mod = mod.active
|
||||
mod.limits[0] = self.down_limits
|
||||
if self.active_modifier_is_simple_deform:
|
||||
self.modifier.limits[0] = self.down_limits
|
||||
|
||||
down_limits: FloatProperty(name='down',
|
||||
description='Lower limit(Green)',
|
||||
|
@ -1,78 +1,147 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
from functools import cache
|
||||
|
||||
import bpy
|
||||
|
||||
from .utils import GizmoUpdate
|
||||
|
||||
gizmo = GizmoUpdate()
|
||||
|
||||
"""depsgraph_update_post cannot listen to users modifying modifier parameters
|
||||
Use timers to watch and use cache
|
||||
"""
|
||||
|
||||
|
||||
class update_public:
|
||||
_event_func_list = {}
|
||||
update_func: 'function'
|
||||
tmp_save_data = {}
|
||||
_events_func_list = {}
|
||||
run_time = 0.2
|
||||
|
||||
@classmethod
|
||||
def timers_update_poll(cls) -> bool:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
@cache
|
||||
def update_poll(cls) -> bool:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _update_func_call_timer(cls):
|
||||
if cls.timers_update_poll():
|
||||
for c, func_list in cls._events_func_list.items():
|
||||
if func_list and c.update_poll():
|
||||
for func in func_list:
|
||||
func()
|
||||
cls.clear_cache_events()
|
||||
return cls.run_time
|
||||
|
||||
@classmethod
|
||||
def clear_cache_events(cls):
|
||||
for cl in cls._events_func_list.keys():
|
||||
if getattr(cl, 'clear_cache', False):
|
||||
cl.clear_cache()
|
||||
|
||||
@classmethod
|
||||
def clear_cache(cls):
|
||||
cls.update_poll.cache_clear()
|
||||
|
||||
@classmethod
|
||||
def append(cls, item):
|
||||
if cls not in cls._events_func_list:
|
||||
cls._events_func_list[cls] = []
|
||||
cls._events_func_list[cls].append(item)
|
||||
|
||||
@classmethod
|
||||
def remove(cls, item):
|
||||
if item in cls._events_func_list[cls]:
|
||||
cls._events_func_list[cls].remove(item)
|
||||
|
||||
# --------------- reg and unreg
|
||||
@classmethod
|
||||
def register(cls):
|
||||
import bpy
|
||||
bpy.app.timers.register(cls.update_func, persistent=True)
|
||||
from bpy.app import timers
|
||||
func = cls._update_func_call_timer
|
||||
if not timers.is_registered(func):
|
||||
timers.register(func, persistent=True)
|
||||
else:
|
||||
print('cls timers is registered', cls)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
from bpy.app import timers
|
||||
func = cls.update_func
|
||||
func = cls._update_func_call_timer
|
||||
if timers.is_registered(func):
|
||||
timers.unregister(func)
|
||||
|
||||
@classmethod
|
||||
def _update_call(cls):
|
||||
for i in cls._event_func_list[cls]:
|
||||
i()
|
||||
|
||||
@classmethod
|
||||
def append(cls, item):
|
||||
if cls not in cls._event_func_list:
|
||||
cls._event_func_list[cls] = []
|
||||
cls._event_func_list[cls].append(item)
|
||||
|
||||
@classmethod
|
||||
def remove(cls, item):
|
||||
if item in cls._event_func_list[cls]:
|
||||
cls._event_func_list[cls].remove(item)
|
||||
else:
|
||||
print('cls timers is not registered', cls)
|
||||
cls._events_func_list.clear()
|
||||
|
||||
|
||||
class change_active_object(update_public):
|
||||
class simple_update(update_public, GizmoUpdate):
|
||||
tmp_save_data = {}
|
||||
from bpy.app.handlers import depsgraph_update_post, persistent
|
||||
handler_type = depsgraph_update_post
|
||||
|
||||
@classmethod
|
||||
def update_func(cls):
|
||||
import bpy
|
||||
name = bpy.context.object.name
|
||||
key = 'active_object'
|
||||
if key not in cls.tmp_save_data or cls.tmp_save_data[key] != name:
|
||||
cls._update_call()
|
||||
cls.tmp_save_data[key] = name
|
||||
return cls.run_time
|
||||
def timers_update_poll(cls):
|
||||
obj = bpy.context.object
|
||||
if not cls.context_mode_is_object():
|
||||
...
|
||||
elif not obj:
|
||||
...
|
||||
elif not cls.obj_type_is_mesh_or_lattice(obj):
|
||||
...
|
||||
elif cls.mod_is_simple_deform_type(obj.modifiers.active):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class change_active_simple_deform_modifier(update_public):
|
||||
class change_active_object(simple_update):
|
||||
@classmethod
|
||||
@cache
|
||||
def update_poll(cls):
|
||||
return cls.is_change_active_object()
|
||||
|
||||
@classmethod
|
||||
def update_func(cls):
|
||||
def is_change_active_object(cls, change_data=True):
|
||||
import bpy
|
||||
obj = bpy.context.object
|
||||
if not obj or obj.type != 'MESH':
|
||||
return cls.run_time
|
||||
|
||||
name = obj.name
|
||||
key = 'active_object'
|
||||
modifiers = cls.get_modifiers_data(obj)
|
||||
change_modifiers = 'modifiers' not in cls.tmp_save_data or cls.tmp_save_data['modifiers'] != modifiers
|
||||
if key not in cls.tmp_save_data or cls.tmp_save_data[key] != name:
|
||||
cls.tmp_save_data['modifiers'] = modifiers
|
||||
if key not in cls.tmp_save_data:
|
||||
if change_data:
|
||||
cls.tmp_save_data[key] = name
|
||||
elif change_modifiers:
|
||||
return True
|
||||
|
||||
elif cls.tmp_save_data[key] != name:
|
||||
if change_data:
|
||||
cls.tmp_save_data[key] = name
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class change_active_simple_deform_modifier(simple_update):
|
||||
|
||||
@classmethod
|
||||
@cache
|
||||
def update_poll(cls):
|
||||
return cls.is_change_active_simple_deform()
|
||||
|
||||
@classmethod
|
||||
def is_change_active_simple_deform(cls) -> bool:
|
||||
import bpy
|
||||
obj = bpy.context.object
|
||||
modifiers = cls.get_modifiers_data(obj)
|
||||
|
||||
def update():
|
||||
cls.tmp_save_data['modifiers'] = modifiers
|
||||
cls._update_call()
|
||||
return cls.run_time
|
||||
|
||||
if change_active_object.update_poll():
|
||||
update()
|
||||
elif 'modifiers' not in cls.tmp_save_data:
|
||||
update()
|
||||
elif cls.tmp_save_data['modifiers'] != modifiers:
|
||||
update()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_modifiers_data(cls, obj):
|
||||
@ -81,20 +150,52 @@ class change_active_simple_deform_modifier(update_public):
|
||||
'modifiers': list(i.name for i in obj.modifiers)}
|
||||
|
||||
|
||||
gizmo = GizmoUpdate()
|
||||
class change_active_modifier_parameter(simple_update):
|
||||
key = 'active_modifier_parameter'
|
||||
|
||||
@classmethod
|
||||
@cache
|
||||
def update_poll(cls):
|
||||
return gizmo.active_modifier_is_simple_deform and cls.is_change_active_simple_parameter()
|
||||
|
||||
@classmethod
|
||||
def update_modifier_parameter(cls, modifier_parameter=None):
|
||||
"""Run this function when the gizmo is updated to avoid duplicate updates
|
||||
"""
|
||||
if not modifier_parameter:
|
||||
modifier_parameter = cls.get_modifiers_parameter(gizmo.modifier)
|
||||
cls.tmp_save_data[cls.key] = modifier_parameter
|
||||
|
||||
@classmethod
|
||||
def change_modifier_parameter(cls) -> bool:
|
||||
mod_data = cls.get_modifiers_parameter(gizmo.modifier)
|
||||
return cls.key in cls.tmp_save_data and cls.tmp_save_data[cls.key] == mod_data
|
||||
|
||||
@classmethod
|
||||
def is_change_active_simple_parameter(cls):
|
||||
parameter = cls.get_modifiers_parameter(gizmo.modifier)
|
||||
if change_active_object.update_poll():
|
||||
cls.update_modifier_parameter(parameter)
|
||||
elif change_active_simple_deform_modifier.update_poll():
|
||||
cls.update_modifier_parameter(parameter)
|
||||
elif cls.key not in cls.tmp_save_data:
|
||||
cls.update_modifier_parameter(parameter)
|
||||
elif cls.tmp_save_data[cls.key] != parameter:
|
||||
cls.update_modifier_parameter(parameter)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def register():
|
||||
change_active_object.register()
|
||||
change_active_simple_deform_modifier.register()
|
||||
simple_update.register()
|
||||
|
||||
change_active_object.append(gizmo.update_multiple_modifiers_data)
|
||||
change_active_simple_deform_modifier.append(gizmo.update_multiple_modifiers_data)
|
||||
def p():
|
||||
gizmo.update_multiple_modifiers_data()
|
||||
|
||||
change_active_object.append(p)
|
||||
change_active_modifier_parameter.append(p)
|
||||
change_active_simple_deform_modifier.append(p)
|
||||
|
||||
|
||||
def unregister():
|
||||
change_active_object.remove(gizmo.update_multiple_modifiers_data)
|
||||
change_active_simple_deform_modifier.remove(gizmo.update_multiple_modifiers_data)
|
||||
|
||||
change_active_object.unregister()
|
||||
change_active_simple_deform_modifier.unregister()
|
||||
simple_update.unregister()
|
||||
|
@ -4,7 +4,6 @@ import math
|
||||
import uuid
|
||||
from functools import cache
|
||||
from os.path import dirname, basename, realpath
|
||||
from time import time
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
@ -13,27 +12,38 @@ from mathutils import Vector, Matrix, Euler
|
||||
|
||||
|
||||
class PublicData:
|
||||
"""Public data class, all fixed data will be placed here
|
||||
"""Public data class, where all fixed data will be placed
|
||||
Classify each different type of data separately and cache it to avoid getting stuck due to excessive update frequency
|
||||
"""
|
||||
G_CustomShape = {}
|
||||
G_GizmoData = {}
|
||||
G_Modifiers_Data = {}
|
||||
G_CustomShape = {} #
|
||||
G_HandleData = {} # Save draw Handle
|
||||
|
||||
G_DeformDrawData = {} # Save Deform Vertex And Indices,Update data only when updating deformation boxes
|
||||
|
||||
G_MultipleModifiersBoundData = {}
|
||||
|
||||
G_INDICES = (
|
||||
(0, 1), (0, 2), (1, 3), (2, 3),
|
||||
(4, 5), (4, 6), (5, 7), (6, 7),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7))
|
||||
|
||||
(0, 4), (1, 5), (2, 6), (3, 7)) # The order in which the 8 points of the bounding box are drawn
|
||||
G_NAME = 'ViewSimpleDeformGizmo_' # Temporary use files prefix
|
||||
G_ADDON_NAME = basename(dirname(realpath(__file__))) # "simple_deform_helper"
|
||||
G_CON_LIMIT_NAME = G_NAME + 'constraints_limit_rotation' # constraints name
|
||||
|
||||
G_MODIFIERS_PROPERTY = [ # copy modifier data
|
||||
G_DEFORM_MESH_NAME = G_NAME + 'DeformMesh'
|
||||
G_TMP_MULTIPLE_MODIFIERS_MESH = 'TMP_' + G_NAME + 'MultipleModifiersMesh'
|
||||
G_SUB_LEVELS = 7
|
||||
|
||||
G_NAME_EMPTY_AXIS = G_NAME + '_Empty_'
|
||||
G_NAME_CON_LIMIT = G_NAME + 'ConstraintsLimitRotation' # constraints name
|
||||
G_NAME_CON_COPY_ROTATION = G_NAME + 'ConstraintsCopyRotation'
|
||||
G_ADDON_NAME = basename(dirname(realpath(__file__))) # "simple_deform_helper"
|
||||
|
||||
G_MODIFIERS_PROPERTY = [ # Copy modifier data
|
||||
'angle',
|
||||
'deform_axis',
|
||||
'deform_method',
|
||||
'factor',
|
||||
'invert_vertex_group',
|
||||
'limits',
|
||||
'limits', # bpy.types.bpy_prop_array
|
||||
'lock_x',
|
||||
'lock_y',
|
||||
'lock_z',
|
||||
@ -72,10 +82,11 @@ class PublicData:
|
||||
def from_selected_obj_generate_json(cls):
|
||||
"""Export selected object vertex data as gizmo custom paint data
|
||||
The output file should be in the blender folder
|
||||
gizmo.json
|
||||
"""
|
||||
import json
|
||||
data = {}
|
||||
for obj in bpy.context.selected_object:
|
||||
for obj in bpy.context.selected_objects:
|
||||
data[obj.name] = cls.from_mesh_get_triangle_face_co(obj.data)
|
||||
print(data)
|
||||
with open('gizmo.json', 'w+') as f:
|
||||
@ -96,6 +107,10 @@ class PublicClass(PublicData):
|
||||
|
||||
|
||||
class PublicPoll(PublicClass):
|
||||
@classmethod
|
||||
def context_mode_is_object(cls) -> bool:
|
||||
return bpy.context.mode == 'OBJECT'
|
||||
|
||||
@classmethod
|
||||
def simple_deform_modifier_is_simple(cls, context):
|
||||
"""
|
||||
@ -112,10 +127,9 @@ class PublicPoll(PublicClass):
|
||||
if not mod:
|
||||
return False
|
||||
|
||||
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'
|
||||
available_obj_type = cls.obj_type_is_mesh_or_lattice(obj)
|
||||
is_available_obj = cls.mod_is_simple_deform_type(mod) and available_obj_type
|
||||
is_obj_mode = cls.context_mode_is_object()
|
||||
show_mod = mod.show_viewport
|
||||
not_is_self_mesh = obj.name != cls.G_NAME
|
||||
return is_available_obj and is_obj_mode and show_mod and not_is_self_mesh
|
||||
@ -159,7 +173,51 @@ class PublicPoll(PublicClass):
|
||||
return poll and not_switch
|
||||
|
||||
|
||||
class PublicUtils(PublicPoll):
|
||||
class PublicTranslate(PublicPoll):
|
||||
@classmethod
|
||||
def translate_text(cls, text):
|
||||
return bpy.app.translations.pgettext(text)
|
||||
|
||||
@classmethod
|
||||
def translate_header_text(cls, mode, value):
|
||||
return cls.translate_text(mode) + ':{}'.format(value)
|
||||
|
||||
|
||||
class GizmoClassMethod(PublicTranslate):
|
||||
|
||||
@classmethod
|
||||
def get_depsgraph(cls, obj: 'bpy.types.Object'):
|
||||
"""
|
||||
@param obj: dep obj
|
||||
@return: If there is no input obj, reverse the active object evaluated
|
||||
"""
|
||||
context = bpy.context
|
||||
if obj is None:
|
||||
obj = context.object
|
||||
dep = context.evaluated_depsgraph_get()
|
||||
return obj.evaluated_get(dep)
|
||||
|
||||
@classmethod
|
||||
def get_vector_axis(cls, mod):
|
||||
axis = mod.deform_axis
|
||||
if 'BEND' == mod.deform_method:
|
||||
vector_axis = Vector((0, 0, 1)) if axis in (
|
||||
'Y', 'X') else Vector((1, 0, 0))
|
||||
else:
|
||||
vector = (Vector((1, 0, 0)) if (
|
||||
axis == 'X') else Vector((0, 1, 0)))
|
||||
vector_axis = Vector((0, 0, 1)) if (
|
||||
axis == 'Z') else vector
|
||||
return vector_axis
|
||||
|
||||
@classmethod
|
||||
def get_modifiers_parameter(cls, modifier):
|
||||
prop = bpy.types.bpy_prop_array
|
||||
return list(
|
||||
getattr(modifier, i)[:] if type(getattr(modifier, i)) == prop else getattr(modifier, i)
|
||||
for i in cls.G_MODIFIERS_PROPERTY
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def value_limit(cls, value, max_value=1, min_value=0):
|
||||
"""
|
||||
@ -183,18 +241,6 @@ class PublicUtils(PublicPoll):
|
||||
"""
|
||||
return number == abs(number)
|
||||
|
||||
@classmethod
|
||||
def get_depsgraph(cls, obj: 'bpy.types.Object'):
|
||||
"""
|
||||
@param obj: dep obj
|
||||
@return: If there is no input obj, reverse the active object evaluated
|
||||
"""
|
||||
context = bpy.context
|
||||
if obj is None:
|
||||
obj = context.object
|
||||
dep = context.evaluated_depsgraph_get()
|
||||
return obj.evaluated_get(dep)
|
||||
|
||||
@classmethod
|
||||
def link_obj_to_active_collection(cls, obj: 'bpy.types.Object'):
|
||||
context = bpy.context
|
||||
@ -203,22 +249,6 @@ class PublicUtils(PublicPoll):
|
||||
objects.link(
|
||||
obj)
|
||||
|
||||
@classmethod
|
||||
def properties_is_modifier(cls) -> bool:
|
||||
"""Returns whether there is a modifier property panel open in the active window.
|
||||
If it is open, it returns to True else False
|
||||
"""
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'PROPERTIES':
|
||||
for space in area.spaces:
|
||||
if space.type == 'PROPERTIES' and space.context == 'MODIFIER':
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def bound_box_to_list(cls, obj: 'bpy.types.Object'):
|
||||
return tuple(i[:] for i in obj.bound_box)
|
||||
|
||||
@classmethod
|
||||
def get_mesh_max_min_co(cls, obj: 'bpy.context.object') -> '[Vector,Vector]':
|
||||
if obj.type == 'MESH':
|
||||
@ -271,36 +301,6 @@ class PublicUtils(PublicPoll):
|
||||
|
||||
return list((aa + bb) / 2 for (aa, bb) in point_list)
|
||||
|
||||
@classmethod
|
||||
def translate_text(cls, text):
|
||||
return bpy.app.translations.pgettext(text)
|
||||
|
||||
@classmethod
|
||||
def translate_header_text(cls, mode, value):
|
||||
return cls.translate_text(mode) + ':{}'.format(value)
|
||||
|
||||
|
||||
class GizmoClassMethod(PublicUtils):
|
||||
@classmethod
|
||||
def get_vector_axis(cls, mod):
|
||||
axis = mod.deform_axis
|
||||
if 'BEND' == mod.deform_method:
|
||||
vector_axis = Vector((0, 0, 1)) if axis in (
|
||||
'Y', 'X') else Vector((1, 0, 0))
|
||||
else:
|
||||
vector = (Vector((1, 0, 0)) if (
|
||||
axis == 'X') else Vector((0, 1, 0)))
|
||||
vector_axis = Vector((0, 0, 1)) if (
|
||||
axis == 'Z') else vector
|
||||
return vector_axis
|
||||
|
||||
@classmethod
|
||||
def get_bound_co_data(cls):
|
||||
if 'co' not in cls.G_GizmoData:
|
||||
cls.G_GizmoData['co'] = cls.get_mesh_max_min_co(
|
||||
bpy.context.object)
|
||||
return cls.G_GizmoData['co']
|
||||
|
||||
@classmethod
|
||||
def tow_co_to_coordinate(cls, data):
|
||||
((min_x, min_y, min_z), (max_x, max_y, max_z)) = data
|
||||
@ -315,6 +315,29 @@ class GizmoClassMethod(PublicUtils):
|
||||
Vector((min_x, max_y, max_z))
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def mod_is_simple_deform_type(cls, mod):
|
||||
return mod and mod.type == 'SIMPLE_DEFORM'
|
||||
|
||||
@classmethod
|
||||
def obj_type_is_mesh_or_lattice(cls, obj: 'bpy.types.Object'):
|
||||
return obj and (obj.type in ('MESH', 'LATTICE'))
|
||||
|
||||
@classmethod
|
||||
def from_vertices_new_mesh(cls, name, vertices):
|
||||
new_mesh = bpy.data.meshes.new(name)
|
||||
new_mesh.from_pydata(vertices, cls.G_INDICES, [])
|
||||
new_mesh.update()
|
||||
return new_mesh
|
||||
|
||||
@classmethod
|
||||
def copy_modifier_parameter(cls, old_mod, new_mod):
|
||||
for prop_name in cls.G_MODIFIERS_PROPERTY:
|
||||
origin_value = getattr(old_mod, prop_name, None)
|
||||
is_array_prop = type(origin_value) == bpy.types.bpy_prop_array
|
||||
value = origin_value[:] if is_array_prop else origin_value
|
||||
setattr(new_mod, prop_name, value)
|
||||
|
||||
|
||||
class PublicProperty(GizmoClassMethod):
|
||||
|
||||
@ -332,15 +355,17 @@ class PublicProperty(GizmoClassMethod):
|
||||
top, bottom, left, right, front, back = self.modifier_bound_box_pos
|
||||
mod = self.modifier
|
||||
g_l = self.__from_up_down_point_get_limits_point
|
||||
if self.modifier.origin:
|
||||
origin = self.modifier.origin
|
||||
if origin:
|
||||
vector_axis = self.get_vector_axis(mod)
|
||||
origin_mat = mod.origin.matrix_basis.to_3x3()
|
||||
axis_ = origin_mat @ vector_axis
|
||||
matrix = self.modifier.origin.matrix_local
|
||||
origin_mat = matrix.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 = self.point_to_angle(i, j, f, axis_)
|
||||
angle = self.point_to_angle(i, j, f, axis)
|
||||
if abs(angle - 180) < 0.00001:
|
||||
up_point, down_point = j, i
|
||||
up_limits, down_limits = g_l(j, i)
|
||||
@ -349,7 +374,6 @@ class PublicProperty(GizmoClassMethod):
|
||||
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
|
||||
else:
|
||||
axis = self.modifier_deform_axis
|
||||
@ -383,28 +407,31 @@ class PublicProperty(GizmoClassMethod):
|
||||
|
||||
@classmethod
|
||||
def clear_cache(cls):
|
||||
cls._each_face_pos.cache_clear()
|
||||
cls.clear_point_cache()
|
||||
cls.clear_modifiers_data()
|
||||
|
||||
@classmethod
|
||||
def clear_point_cache(cls):
|
||||
cls._get_limits_point_and_bound_box_co.cache_clear()
|
||||
|
||||
@classmethod
|
||||
def clear_data(cls):
|
||||
cls.G_GizmoData.clear()
|
||||
def clear_modifiers_data(cls):
|
||||
cls.G_MultipleModifiersBoundData.clear()
|
||||
|
||||
@classmethod
|
||||
def clear_modifiers_data(cls):
|
||||
cls.G_Modifiers_Data.clear()
|
||||
def clear_deform_data(cls):
|
||||
cls.G_DeformDrawData.clear()
|
||||
|
||||
# --------------- Cache Data ----------------------
|
||||
|
||||
@property
|
||||
def each_face_pos(self):
|
||||
matrix = Matrix()
|
||||
matrix.freeze()
|
||||
return self._each_face_pos(matrix, self.get_bound_co_data())
|
||||
|
||||
@property
|
||||
def modifier_bound_co(self):
|
||||
return self.G_Modifiers_Data.get(self.modifier.name, self.get_bound_co_data())
|
||||
def get_bound_co_data():
|
||||
key = 'self.modifier.name'
|
||||
if key not in self.G_MultipleModifiersBoundData:
|
||||
self.G_MultipleModifiersBoundData[key] = self.get_mesh_max_min_co(self.obj)
|
||||
return self.G_MultipleModifiersBoundData[key]
|
||||
|
||||
return self.G_MultipleModifiersBoundData.get(self.modifier.name, get_bound_co_data())
|
||||
|
||||
@property
|
||||
def modifier_bound_box_pos(self):
|
||||
@ -423,13 +450,12 @@ class PublicProperty(GizmoClassMethod):
|
||||
return self.matrix_calculation(self.obj_matrix_world, bound)
|
||||
|
||||
@property
|
||||
def modifier_origin_angle_is_available(self):
|
||||
def modifier_origin_is_available(self):
|
||||
try:
|
||||
self._get_limits_point_and_bound_box_co()
|
||||
return True
|
||||
except UnboundLocalError:
|
||||
print('modifier_origin_angle_is_available')
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
return False
|
||||
|
||||
# --------------- Compute Data ----------------------
|
||||
@ -471,6 +497,11 @@ class PublicProperty(GizmoClassMethod):
|
||||
if self.active_modifier_is_simple_deform:
|
||||
return self.modifier.deform_method in ('TWIST', 'BEND')
|
||||
|
||||
@property
|
||||
def modifier_deform_method_is_bend(self):
|
||||
if self.active_modifier_is_simple_deform:
|
||||
return self.modifier.deform_method == 'BEND'
|
||||
|
||||
@property
|
||||
def modifier_up_limits(self):
|
||||
if self.modifier:
|
||||
@ -483,7 +514,7 @@ class PublicProperty(GizmoClassMethod):
|
||||
|
||||
@property
|
||||
def active_modifier_is_simple_deform(self):
|
||||
return self.modifier and self.modifier.type == 'SIMPLE_DEFORM'
|
||||
return self.mod_is_simple_deform_type(self.modifier)
|
||||
|
||||
# ----- point
|
||||
@property
|
||||
@ -526,7 +557,11 @@ class PublicProperty(GizmoClassMethod):
|
||||
|
||||
@property
|
||||
def modifier_is_use_origin_axis(self):
|
||||
return self.obj_origin_property_group.origin_mode != 'NOT' and not self.modifier.origin
|
||||
return self.obj_origin_property_group.origin_mode != 'NOT'
|
||||
|
||||
@property
|
||||
def modifier_is_have_origin(self):
|
||||
return self.modifier_is_use_origin_axis and self.modifier.origin
|
||||
|
||||
|
||||
class GizmoUpdate(PublicProperty):
|
||||
@ -543,7 +578,7 @@ class GizmoUpdate(PublicProperty):
|
||||
if origin.parent != obj:
|
||||
origin.parent = obj
|
||||
origin.rotation_euler.zero()
|
||||
if not self.modifier_origin_angle_is_available:
|
||||
if not self.modifier_origin_is_available:
|
||||
origin.location.zero()
|
||||
origin.scale = 1, 1, 1
|
||||
|
||||
@ -552,7 +587,7 @@ class GizmoUpdate(PublicProperty):
|
||||
obj = self.obj
|
||||
origin = mod.origin
|
||||
if not origin:
|
||||
new_name = self.G_NAME + '_Empty_' + str(uuid.uuid4())
|
||||
new_name = self.G_NAME_EMPTY_AXIS + str(uuid.uuid4())
|
||||
origin_object = bpy.data.objects.new(new_name, None)
|
||||
self.link_obj_to_active_collection(origin_object)
|
||||
origin_object.hide_set(True)
|
||||
@ -564,7 +599,7 @@ class GizmoUpdate(PublicProperty):
|
||||
if origin_object == obj:
|
||||
return
|
||||
# add constraints
|
||||
name = self.G_CON_LIMIT_NAME
|
||||
name = self.G_NAME_CON_LIMIT
|
||||
if origin_object.constraints.keys().__len__() > 2:
|
||||
origin_object.constraints.clear()
|
||||
if name in origin_object.constraints.keys():
|
||||
@ -579,7 +614,7 @@ class GizmoUpdate(PublicProperty):
|
||||
limit_constraints.use_limit_x = True
|
||||
limit_constraints.use_limit_y = True
|
||||
limit_constraints.use_limit_z = True
|
||||
con_copy_name = self.G_NAME + 'constraints_copy_rotation'
|
||||
con_copy_name = self.G_NAME_CON_COPY_ROTATION
|
||||
if con_copy_name in origin_object.constraints.keys():
|
||||
copy_constraints = origin.constraints.get(con_copy_name)
|
||||
else:
|
||||
@ -590,16 +625,15 @@ class GizmoUpdate(PublicProperty):
|
||||
copy_constraints.mix_mode = 'BEFORE'
|
||||
copy_constraints.target_space = 'WORLD'
|
||||
copy_constraints.owner_space = 'WORLD'
|
||||
origin_mode = self.obj.SimpleDeformGizmo_PropertyGroup.origin_mode
|
||||
origin_object.SimpleDeformGizmo_PropertyGroup.origin_mode = origin_mode
|
||||
self.fix_origin_parent_and_angle()
|
||||
return origin_object
|
||||
|
||||
def update_object_origin_matrix(self):
|
||||
st = time()
|
||||
if self.modifier_is_have_origin:
|
||||
origin_mode = self.origin_mode
|
||||
origin_object = self.modifier.origin
|
||||
is_use = self.modifier_is_use_origin_axis
|
||||
|
||||
if origin_object and is_use:
|
||||
if origin_mode == 'UP_LIMITS':
|
||||
origin_object.matrix_world.translation = Vector(self.point_limits_up)
|
||||
elif origin_mode == 'DOWN_LIMITS':
|
||||
@ -610,80 +644,106 @@ class GizmoUpdate(PublicProperty):
|
||||
elif origin_mode == 'MIDDLE':
|
||||
translation = (self.point_up + self.point_down) / 2
|
||||
origin_object.matrix_world.translation = translation
|
||||
print('update_object_origin_matrix', time() - st)
|
||||
|
||||
def update_multiple_modifiers_data(self):
|
||||
print('update_multiple_modifiers_data', self)
|
||||
st = time()
|
||||
obj = self.obj
|
||||
context = bpy.context
|
||||
if obj.type not in ('MESH', 'LATTICE') or not self.simple_deform_public_poll(context):
|
||||
if not self.obj_type_is_mesh_or_lattice(obj) or not self.simple_deform_modifier_is_simple(context):
|
||||
return
|
||||
self.clear_cache()
|
||||
self.clear_point_cache()
|
||||
self.clear_modifiers_data()
|
||||
data = bpy.data
|
||||
name = self.G_NAME
|
||||
origin_object = data.objects.get(name)
|
||||
name = self.G_TMP_MULTIPLE_MODIFIERS_MESH
|
||||
|
||||
# update multiple simple_deform bound data
|
||||
if origin_object:
|
||||
data.objects.remove(origin_object)
|
||||
# del old tmp object
|
||||
old_object = data.objects.get(name)
|
||||
if old_object:
|
||||
data.objects.remove(old_object)
|
||||
|
||||
if data.meshes.get(name):
|
||||
data.meshes.remove(data.meshes.get(name))
|
||||
|
||||
vertices = self.tow_co_to_coordinate(self.get_bound_co_data())
|
||||
new_mesh = data.meshes.new(name)
|
||||
new_mesh.from_pydata(vertices, self.G_INDICES, [])
|
||||
new_mesh.update()
|
||||
deform_obj = data.objects.new(name, new_mesh)
|
||||
"""get origin mesh bound box as multiple basic mesh
|
||||
add multiple modifiers and get depsgraph obj bound box
|
||||
"""
|
||||
vertices = self.tow_co_to_coordinate(self.get_mesh_max_min_co(self.obj))
|
||||
new_mesh = self.from_vertices_new_mesh(name, vertices)
|
||||
modifiers_obj = data.objects.new(name, new_mesh)
|
||||
|
||||
self.link_obj_to_active_collection(deform_obj)
|
||||
if deform_obj == obj:
|
||||
self.link_obj_to_active_collection(modifiers_obj)
|
||||
if modifiers_obj == obj: # is cycles
|
||||
return
|
||||
if deform_obj.parent != obj:
|
||||
deform_obj.parent = obj
|
||||
if modifiers_obj.parent != obj:
|
||||
modifiers_obj.parent = obj
|
||||
|
||||
deform_obj.modifiers.clear()
|
||||
subdivision = deform_obj.modifiers.new('1', 'SUBSURF')
|
||||
subdivision.levels = 7
|
||||
self.G_GizmoData['co'] = self.get_bound_co_data()
|
||||
modifiers_obj.modifiers.clear()
|
||||
subdivision = modifiers_obj.modifiers.new('1', 'SUBSURF')
|
||||
subdivision.levels = self.G_SUB_LEVELS
|
||||
|
||||
for mo in context.object.modifiers:
|
||||
if mo.type == 'SIMPLE_DEFORM':
|
||||
obj = self.get_depsgraph(deform_obj)
|
||||
self.G_Modifiers_Data[mo.name] = self.get_mesh_max_min_co(obj)
|
||||
simple_deform = deform_obj.modifiers.new(
|
||||
mo.name, 'SIMPLE_DEFORM')
|
||||
simple_deform.deform_method = mo.deform_method
|
||||
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
|
||||
deform_obj.hide_select = True
|
||||
deform_obj.hide_set(True)
|
||||
deform_obj.hide_viewport = False
|
||||
deform_obj.hide_render = True
|
||||
deform_obj.hide_viewport = True
|
||||
deform_obj.hide_set(True)
|
||||
print('multiple_modifiers', time() - st)
|
||||
for mod in context.object.modifiers:
|
||||
if self.mod_is_simple_deform_type(mod):
|
||||
dep_bound_tow_co = self.get_mesh_max_min_co(self.get_depsgraph(modifiers_obj))
|
||||
self.G_MultipleModifiersBoundData[mod.name] = dep_bound_tow_co
|
||||
new_mod = modifiers_obj.modifiers.new(mod.name, 'SIMPLE_DEFORM')
|
||||
self.copy_modifier_parameter(mod, new_mod)
|
||||
data.objects.remove(modifiers_obj)
|
||||
|
||||
def update_deform_wireframe(self, obj):
|
||||
def update_deform_wireframe(self):
|
||||
if not self.pref.update_deform_wireframe:
|
||||
return
|
||||
# obj = self.obj
|
||||
name = self.modifier.name
|
||||
deform_name = self.G_DEFORM_MESH_NAME
|
||||
|
||||
co = self.G_MultipleModifiersBoundData[name]
|
||||
|
||||
deform_obj = bpy.data.objects.get(deform_name, None)
|
||||
|
||||
if not deform_obj:
|
||||
a, b = 0.5, -0.5
|
||||
vertices = self.tow_co_to_coordinate(((b, b, b), (a, a, a)))
|
||||
new_mesh = self.from_vertices_new_mesh(name, vertices)
|
||||
deform_obj = bpy.data.objects.new(deform_name, new_mesh)
|
||||
deform_obj.hide_select = True
|
||||
# deform_obj.hide_set(True)
|
||||
deform_obj.hide_render = True
|
||||
deform_obj.hide_viewport = True
|
||||
|
||||
self.link_obj_to_active_collection(deform_obj)
|
||||
|
||||
deform_obj.parent = self.obj
|
||||
|
||||
tmv = deform_obj.hide_viewport
|
||||
tmh = deform_obj.hide_get()
|
||||
deform_obj.hide_viewport = False
|
||||
deform_obj.hide_set(False)
|
||||
|
||||
# Update Matrix
|
||||
deform_obj.matrix_world = Matrix()
|
||||
center = (co[0] + co[1]) / 2
|
||||
scale = co[1] - co[0]
|
||||
deform_obj.matrix_world = self.obj_matrix_world @ deform_obj.matrix_world
|
||||
deform_obj.location = center
|
||||
deform_obj.scale = scale
|
||||
|
||||
# Update Modifier data
|
||||
mods = deform_obj.modifiers
|
||||
mods.clear()
|
||||
subdivision = mods.new('1', 'SUBSURF')
|
||||
subdivision.levels = self.G_SUB_LEVELS
|
||||
|
||||
new_mod = mods.new(name, 'SIMPLE_DEFORM')
|
||||
self.copy_modifier_parameter(self.modifier, new_mod)
|
||||
|
||||
# Get vertices data
|
||||
context = bpy.context
|
||||
matrix = self.obj_matrix_world.copy()
|
||||
obj = self.get_depsgraph(deform_obj)
|
||||
matrix = deform_obj.matrix_world.copy()
|
||||
ver_len = obj.data.vertices.__len__()
|
||||
edge_len = obj.data.edges.__len__()
|
||||
|
||||
if 'numpy_data' not in self.G_GizmoData:
|
||||
self.G_GizmoData['numpy_data'] = {}
|
||||
|
||||
numpy_data = self.G_GizmoData['numpy_data']
|
||||
if 'numpy_data' not in self.G_DeformDrawData:
|
||||
self.G_DeformDrawData['numpy_data'] = {}
|
||||
numpy_data = self.G_DeformDrawData['numpy_data']
|
||||
key = (ver_len, edge_len)
|
||||
if key in numpy_data:
|
||||
list_edges, list_vertices = numpy_data[key]
|
||||
@ -702,10 +762,13 @@ class GizmoUpdate(PublicProperty):
|
||||
obj.data.edges.foreach_get('vertices', list_edges)
|
||||
indices = list_edges.reshape((edge_len, 2))
|
||||
|
||||
modifiers = self.get_modifiers_parameter(self.modifier)
|
||||
limits = context.object.modifiers.active.limits[:]
|
||||
modifiers = [getattr(context.object.modifiers.active, i)
|
||||
for i in self.G_MODIFIERS_PROPERTY]
|
||||
self.G_GizmoData['simple_deform_box_data'] = (ver, indices, matrix, modifiers, limits[:])
|
||||
|
||||
deform_obj.hide_viewport = tmv
|
||||
deform_obj.hide_set(tmh)
|
||||
|
||||
self.G_DeformDrawData['simple_deform_bound_data'] = (ver, indices, self.obj_matrix_world, modifiers, limits[:])
|
||||
|
||||
|
||||
class GizmoUtils(GizmoUpdate):
|
||||
@ -748,16 +811,16 @@ class GizmoUtils(GizmoUpdate):
|
||||
|
||||
def __update_matrix_func(self, context):
|
||||
func = getattr(self, 'update_gizmo_matrix', None)
|
||||
if func and self.modifier_origin_angle_is_available:
|
||||
if func and self.modifier_origin_is_available:
|
||||
func(context)
|
||||
|
||||
def draw(self, context):
|
||||
if self.modifier_origin_angle_is_available:
|
||||
if self.modifier_origin_is_available:
|
||||
self.draw_custom_shape(self.custom_shape[self.draw_type])
|
||||
self.__update_matrix_func(context)
|
||||
|
||||
def draw_select(self, context, select_id):
|
||||
if self.modifier_origin_angle_is_available:
|
||||
if self.modifier_origin_is_available:
|
||||
self.draw_custom_shape(
|
||||
self.custom_shape[self.draw_type], select_id=select_id)
|
||||
self.__update_matrix_func(context)
|
||||
@ -788,6 +851,11 @@ class GizmoUtils(GizmoUpdate):
|
||||
self.pref.update_deform_wireframe = self.pref.update_deform_wireframe ^ True
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
@staticmethod
|
||||
def tag_redraw(context):
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
|
||||
|
||||
class GizmoGroupUtils(GizmoUtils):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
@ -848,6 +916,22 @@ class Tmp:
|
||||
rot = rot.to_matrix()
|
||||
self.matrix_basis = self.matrix_basis @ rot.to_4x4()
|
||||
|
||||
@classmethod
|
||||
def bound_box_to_list(cls, obj: 'bpy.types.Object'):
|
||||
return tuple(i[:] for i in obj.bound_box)
|
||||
|
||||
@classmethod
|
||||
def properties_is_modifier(cls) -> bool:
|
||||
"""Returns whether there is a modifier property panel open in the active window.
|
||||
If it is open, it returns to True else False
|
||||
"""
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'PROPERTIES':
|
||||
for space in area.spaces:
|
||||
if space.type == 'PROPERTIES' and space.context == 'MODIFIER':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def register():
|
||||
PublicData.load_gizmo_data()
|
||||
|
Loading…
Reference in New Issue
Block a user