Skip to content

Commit e83d684

Browse files
committed
0.1.81 Performance and Bug Fix Update
- Applying a modifer in edit mode with [modifer key](https://www.notion.so/Extra-de3a011e64b2403a94eeb2d6bc2f12df?pvs=21) (A) is now theoretically up to 1000x faster or more in some situations, but more realistically usually around 2-5x faster. This is with an experimental optimization. - Unwrap in Place is now up to 10x faster in some cases when heavy modifers are used. - By optimizing many of the functions, Unwrap in Place on simple meshes with no modifers present should be general faster, from 0.039ms to 0.0265ms and from 2.9s to 1.3s Unwrap in Place is now almost as fast as the regular unwrap on a singel object, 5s vs 4.5s on 63k tris. - It is now up to 3x faster when unwraping many objects at once. - Unwrap in Place with uv sync off on many objects (totall 4mil tris) in edit mode whent from 39s to to 4s. - Fix so that hide state stays the same after an unwrap inplace with uv sync turned off. - A bug that prevented Unwrap in Place from unwraping an object sometimes correctly is now fixed. - The active modifer index is now restored after using Unwrap in Place so the active modifer will stay the same. - Fixed many bugs that was introduced because of 4.1 - New option in fast merge (defualt now) to merge to nearest vert if no activ vert can be found
1 parent 1adaaa7 commit e83d684

10 files changed

+1060
-887
lines changed

__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
bl_info = {
1919
"name": "Key Ops: Toolkit",
2020
"author": "DanGry, MACHIN3",
21-
"version": (0, 1, 80),
21+
"version": (0, 1, 81),
2222
"blender": (4, 0, 0),
2323
"description": "Adds new tools, shortcuts and operations to Blender",
2424
"category": "3D View"
@@ -97,7 +97,7 @@
9797
default_classes.append(AutoSmooth)
9898

9999
def register():
100-
debug = True
100+
debug = False
101101
global classes, keymaps
102102
global default_classes
103103

addon_preferences.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def check_delete_menu_keymap():
175175
row = column.row()
176176
row.label(text="Fast Merge")
177177
row.alignment = 'LEFT'
178-
row.prop(self, "fast_merge_last")
178+
row.prop(self, "fast_merge_merge_options")
179179
row.prop(self, "fast_merge_soft_limit")
180180
if self.fast_merge_soft_limit == "max_polycount" or self.fast_merge_soft_limit == "max_limit_&_all_selected":
181181
row.prop(self, "fast_merge_polycount")
@@ -430,7 +430,7 @@ def update_enable(self, context):
430430
enable_double_click_select_island: BoolProperty(name="Double Click Select Island", description="Double Click to Select Mesh Island like in Maya", default=True, update=enable_deco("double_click_select_island")) # type: ignore
431431
enable_smart_seam: BoolProperty(name="Smart seam", default=False, update=enable_deco("smart_seam")) # type: ignore
432432
enable_uv_tools: BoolProperty(name="UV Tools", default=True, update=enable_deco("uv_tools")) # type: ignore
433-
enable_uv_pies: BoolProperty(name="UV Pies", default=False, update=enable_deco("uv_pies")) # type: ignore
433+
enable_uv_pies: BoolProperty(name="UV Pies", default=True, update=enable_deco("uv_pies")) # type: ignore
434434
enable_utility_pie: BoolProperty(name="Utility Pie", default=True, update=enable_deco("utility_pie")) # type: ignore
435435
enable_add_objects_pie: BoolProperty(name="Add Objects Pie", default=True, update=enable_deco("add_objects_pie")) # type: ignore
436436
enable_view_camera_pie: BoolProperty(name="View Camera Pie", default=False, update=enable_deco("view_camera_pie")) # type: ignore
@@ -479,7 +479,13 @@ def update_enable(self, context):
479479
("HOLD", "Hold", "Hold key to move Pivot")],
480480
default="HOLD") # type: ignore
481481
maya_pivot_show_gizmo: BoolProperty(name="Show Gizmo", default=True) # type: ignore
482-
fast_merge_last: BoolProperty(name="Always merge nerast", default=False) # type: ignore
482+
fast_merge_merge_options: EnumProperty(
483+
name="Options",
484+
items=[
485+
("merge to nerest vert if no active", "Merge to nearest if no active and over 1 vert is selected", "Merge to nearest vert if no active vert and over 1 vert is selected"),
486+
("always merge to nearest vert", "Always merge to nearest vert", "Always merge to nearest vert"),
487+
("only merge if active or only 1 verts is selected", "only merge to nearest if 1 vert is selected, otherwise to active vert", "(legacy) only merge if active vert or only 1 verts is selected")],
488+
default="merge to nerest vert if no active") # type: ignore
483489
fast_merge_soft_limit: EnumProperty(
484490
name="Limit",
485491
items=[

menu/pies.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,11 @@ def draw(self, context):
183183
# else:
184184
pie.operator("uv.keyops_quick_pack", text="Quick Pack", icon="CON_SAMEVOL") #BOTTOM
185185

186-
pie.operator("uv.unwrap", text="Unwrap and Pack", icon="UV_FACESEL") #TOP
186+
pie.operator("uv.keyops_unwrap_in_place", text="Unwrap Inplace", icon="STICKY_UVS_VERT") #TOP
187187

188-
pie.operator("keyops.unwrap_selected", text="Unwrap Selected", icon="UV_VERTEXSEL") #LEFT TOP
188+
pie.operator("uv.unwrap", text="Unwrap and Pack", icon="UV_FACESEL") #LEFT TOP
189189

190-
pie.operator("uv.keyops_unwrap_in_place", text="Unwrap Inplace", icon="STICKY_UVS_VERT") #RIGHT TOP
190+
pie.operator("keyops.unwrap_selected", text="Unwrap Selected", icon="UV_VERTEXSEL") #RIGHT TOP
191191

192192
if uvtoolkit and zenuv:
193193
if bpy.context.tool_settings.use_uv_select_sync:

operators/add_mesh.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def draw_scale_prop(self, layout):
4545
def AddModCylinder(context, segment_amount, scale, use_relative_scale, scale_relative_float, scale_property):
4646
if bpy.context.mode == 'EDIT_MESH':
4747
bpy.ops.object.editmode_toggle()
48-
49-
bpy.ops.mesh.primitive_plane_add(size=2, enter_editmode=True, align='WORLD', scale=(1, 1, 1))
48+
bpy.ops.mesh.primitive_plane_add(size=2, enter_editmode=False, align='WORLD', scale=(1, 1, 1))
49+
bpy.ops.object.editmode_toggle()
5050
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
5151
bpy.ops.mesh.edge_collapse()
5252
bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"use_normal_flip":False, "use_dissolve_ortho_edges":False, "mirror":False}, TRANSFORM_OT_translate={"value":(1, 0, 0), "orient_type":'GLOBAL', "orient_matrix":((1, 0, 0), (0, 1, 0), (0, 0, 1)), "orient_matrix_type":'GLOBAL', "constraint_axis":(True, False, False), "mirror":False, "use_proportional_edit":False, "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "use_proportional_connected":False, "use_proportional_projected":False, "snap":False, "snap_elements":{'VERTEX'}, "use_snap_project":False, "snap_target":'CLOSEST', "use_snap_self":True, "use_snap_edit":True, "use_snap_nonedit":True, "use_snap_selectable":False, "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0),})
@@ -58,7 +58,6 @@ def AddModCylinder(context, segment_amount, scale, use_relative_scale, scale_rel
5858

5959
bpy.ops.object.modifier_add(type='SCREW')
6060
bpy.context.object.modifiers["Screw"].name = "Cylinder"
61-
bpy.ops.object.shade_smooth(use_auto_smooth=True, auto_smooth_angle=1.0472)
6261
bpy.context.object.modifiers["Cylinder"].use_smooth_shade = True
6362
bpy.context.object.modifiers["Cylinder"].steps = segment_amount
6463
bpy.context.object.modifiers["Cylinder"].use_normal_calculate = True
@@ -72,6 +71,8 @@ def AddModCylinder(context, segment_amount, scale, use_relative_scale, scale_rel
7271
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
7372
bpy.context.object.modifiers["Cylinder"].use_merge_vertices = True
7473
bpy.context.object.modifiers["Cylinder"].merge_threshold = scale * 0.1
74+
if bpy.app.version <= (4, 0, 2):
75+
bpy.ops.object.shade_smooth(use_auto_smooth=True, auto_smooth_angle=1.0472)
7576

7677
def AddQuadSphere(context, scale, use_relative_scale, scale_relative_float, scale_property, sub_amount, use_modifiers):
7778
scale = calculate_scale(context, scale_property, use_relative_scale, scale_relative_float, custom_scale_factor=1.0)
@@ -83,7 +84,7 @@ def AddQuadSphere(context, scale, use_relative_scale, scale_relative_float, scal
8384
bpy.ops.object.modifier_add(type='CAST')
8485
bpy.context.object.modifiers["Cast"].factor = 1
8586
bpy.ops.object.shade_smooth()
86-
bpy.ops.transform.resize(value=(1.168, 1.168, 1.168), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=False, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False, snap=False, snap_elements={'INCREMENT'}, use_snap_project=False, snap_target='CLOSEST', use_snap_self=True, use_snap_edit=True, use_snap_nonedit=True, use_snap_selectable=False, alt_navigation=True)
87+
bpy.ops.transform.resize(value=(1.168, 1.168, 1.168), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=False, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False, snap=False, snap_elements={'INCREMENT'}, use_snap_project=False, snap_target='CLOSEST', use_snap_self=True, use_snap_edit=True, use_snap_nonedit=True, use_snap_selectable=False)
8788
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
8889

8990
if not use_modifiers:

operators/auto_smooth.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,4 @@ def unregister():
129129
def draw_menu(self, context):
130130
if context.active_object is not None:
131131
layout = self.layout
132-
layout.operator(AutoSmooth.bl_idname, text="Auto Smooth")
132+
layout.operator(AutoSmooth.bl_idname, text="Auto Smooth")

operators/fast_merge.py

+26-14
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ class FastMerge(bpy.types.Operator):
2424
bl_description = "Fast Merge"
2525
bl_options = {'REGISTER', 'UNDO'}
2626

27-
preserve_uvs: bpy.props.BoolProperty(name="Preserve UVs", description="Try Preserve UVs (Slow)", default=False) # type: ignore
27+
preserve_uvs: bpy.props.BoolProperty(name="Preserve UVs", description="Try Preserve UVs (Slower and does not always work)", default=False) # type: ignore
2828
prefs = get_keyops_prefs()
2929
mouse_position = Vector((0, 0))
30+
draw_preserve_uvs = False
3031

3132
@classmethod
3233
def poll(cls, context):
@@ -38,14 +39,19 @@ def invoke(self, context, event):
3839
return self.execute(context)
3940

4041
def draw(self, context):
41-
if len(self.selected_verts) != 1:
42-
self.layout.prop(self, "preserve_uvs")
42+
self.layout.prop(self, "preserve_uvs")
4343

4444
def execute(self, context):
4545
bm = bmesh.from_edit_mesh(context.active_object.data)
4646
selected_verts = [vert for vert in bm.verts if vert.select]
47+
4748
def merge(self, context, bm=bm, selected_verts=selected_verts):
48-
if len(selected_verts) == 1 or self.prefs.fast_merge_last:
49+
active_vert = bm.select_history.active
50+
if not selected_verts == None:
51+
if len(selected_verts) == 0:
52+
self.report({'WARNING'}, "No vertices selected")
53+
return {'FINISHED'}
54+
if len(selected_verts) == 1 and self.prefs.fast_merge_merge_options == "only merge if active or only 1 verts is selected" or self.prefs.fast_merge_merge_options == "always merge to nearest vert" or self.prefs.fast_merge_merge_options == "merge to nerest vert if no active" and active_vert == None or len(selected_verts) == 1:
4955
obj = context.object
5056
matrix_world = obj.matrix_world.copy()
5157
bm = bmesh.from_edit_mesh(obj.data)
@@ -76,18 +82,24 @@ def merge(self, context, bm=bm, selected_verts=selected_verts):
7682
else:
7783
bmesh.ops.pointmerge(bm, verts=selected_verts, merge_co=nearest_vertex.co)
7884
bmesh.update_edit_mesh(obj.data)
79-
85+
86+
self.report({'INFO'}, "Merged %d vertices" % (len(selected_verts) - 1))
8087
return {'FINISHED'}
81-
88+
8289
else:
83-
selected_history = bm.select_history.active
84-
active_edge = selected_history if selected_history in selected_verts else []
90+
active_vert = bm.select_history.active
8591

86-
if active_edge:
92+
if active_vert is not None:
8793
if self.preserve_uvs:
94+
amount_of_verts_merged = len(selected_verts)
8895
bpy.ops.mesh.merge(uvs=True, type='LAST')
8996
else:
90-
bpy.ops.mesh.merge(type='LAST')
97+
amount_of_verts_merged = len(selected_verts)
98+
bmesh.ops.pointmerge(bm, verts=selected_verts, merge_co=active_vert.co)
99+
bmesh.update_edit_mesh(context.active_object.data)
100+
101+
self.report({'INFO'}, "Merged %d vertices" % (amount_of_verts_merged - 1))
102+
91103
else:
92104
self.report({'WARNING'}, "No Active Vertex to Merge to")
93105

@@ -97,18 +109,18 @@ def merge(self, context, bm=bm, selected_verts=selected_verts):
97109
if self.prefs.fast_merge_polycount >= len(selected_verts):
98110
merge(self, context, bm, selected_verts)
99111
else:
100-
self.report({'WARNING'}, "Too many vertices selected")
112+
self.report({'WARNING'}, "Limit - Too many vertices selected")
101113
elif self.prefs.fast_merge_soft_limit == "all_selected":
102114
if len(selected_verts) == len(bm.verts):
103-
self.report({'WARNING'}, "All vertices are selected")
115+
self.report({'WARNING'}, "Limit - All vertices are selected")
104116
else:
105117
merge(self, context, bm, selected_verts)
106118
elif self.prefs.fast_merge_soft_limit == "max_limit_&_all_selected":
107119
if len(selected_verts) == len(bm.verts) and self.prefs.fast_merge_polycount < len(selected_verts):
108-
self.report({'WARNING'}, "All vertices are selected")
120+
self.report({'WARNING'}, "Limit - All vertices are selected and too many vertices selected")
109121
elif self.prefs.fast_merge_polycount >= len(selected_verts):
110122
merge(self, context, bm, selected_verts)
111123
else:
112-
self.report({'WARNING'}, "Too many vertices selected")
124+
self.report({'WARNING'}, "Limit - Too many vertices selected")
113125

114126
return {'FINISHED'}

operators/modi_key.py

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import bpy.types
33
from bpy.types import Context, Operator
44
from ..utils.pref_utils import get_is_addon_enabled
5+
from ..utils.mesh_utils import modifier_toggle_visability_based
6+
import time
57

68
modifier_list = None
79

@@ -59,17 +61,53 @@ def execute(self, context):
5961
obj.modifiers.remove(active_modifier)
6062
bpy.ops.object.mode_set(mode=current_mode)
6163
elif self.type == 'Apply':
64+
name = active_modifier.name
65+
apply_time = time.time()
66+
6267
if modifier_list:
68+
visibility_modifier_dict_list = {}
69+
70+
def modifier_toggle_visability_based2():
71+
active_object_name = bpy.context.view_layer.objects.active.name
72+
73+
if active_object_name not in visibility_modifier_dict_list:
74+
visibility_modifier_dict_list[active_object_name] = []
75+
76+
visibility_modifier_list = visibility_modifier_dict_list[active_object_name]
77+
78+
if len(visibility_modifier_list) <= 0:
79+
ml_act_ob = bpy.context.view_layer.objects.active
80+
for mod in ml_act_ob.modifiers:
81+
if mod.show_viewport:
82+
visibility_modifier_list.append(mod)
83+
mod.show_viewport = False
84+
else:
85+
ml_act_ob = bpy.context.view_layer.objects.active
86+
hidden_modifiers = []
87+
for mod in ml_act_ob.modifiers:
88+
if mod in visibility_modifier_list:
89+
mod.show_viewport = True
90+
hidden_modifiers.append(mod)
91+
visibility_modifier_list = [mod for mod in visibility_modifier_list if mod not in hidden_modifiers]
92+
visibility_modifier_dict_list[active_object_name] = visibility_modifier_list
93+
94+
if bpy.context.mode == 'EDIT_MESH':
95+
modifier_toggle_visability_based2()
6396
bpy.ops.object.ml_modifier_apply("INVOKE_DEFAULT")
97+
if bpy.context.mode == 'EDIT_MESH':
98+
modifier_toggle_visability_based2()
6499
else:
65100
if bpy.context.mode == 'OBJECT':
66101
bpy.ops.object.modifier_apply(modifier=active_modifier.name)
67102
else:
103+
modifier_toggle_visability_based2()
68104
current_mode = bpy.context.object.mode
69105
bpy.ops.object.mode_set(mode='OBJECT')
70106
bpy.ops.ed.undo_push()
71107
bpy.ops.object.modifier_apply(modifier=active_modifier.name)
72108
bpy.ops.object.mode_set(mode=current_mode)
109+
modifier_toggle_visability_based2()
110+
self.report({'INFO'}, f"Applied {name} in {time.time() - apply_time:.3f} seconds")
73111

74112
elif self.type == 'Apply_All':
75113
bpy.ops.object.convert(target='MESH')

0 commit comments

Comments
 (0)