Optimzation Panel Re-Added
- Major Improvements all round, Join Meshes improved, Combined Materials, Remove Doubles Improvements.
This commit is contained in:
+83
-4
@@ -146,12 +146,12 @@ def validate_symmetry(bones: Dict[str, bpy.types.Bone], base: str, left: str, ri
|
||||
right_exists = any(pattern in bones for pattern in right_patterns)
|
||||
|
||||
return left_exists and right_exists
|
||||
|
||||
|
||||
|
||||
def auto_select_single_armature(context: bpy.types.Context) -> None:
|
||||
"""Automatically select armature if only one exists in scene"""
|
||||
armatures = get_armature_list(context)
|
||||
if len(armatures) == 1:
|
||||
if len(armatures) == 1 and armatures[0][0] != 'NONE':
|
||||
toolkit = context.scene.avatar_toolkit
|
||||
set_active_armature(context, armatures[0])
|
||||
|
||||
def clear_default_objects() -> None:
|
||||
@@ -305,4 +305,83 @@ def apply_armature_to_mesh_with_shapekeys(armature_obj: Object, mesh_obj: Object
|
||||
sk.mute = mute
|
||||
|
||||
mesh_obj.active_shape_key_index = old_active_index
|
||||
mesh_obj.show_only_shape_key = old_show_only
|
||||
mesh_obj.show_only_shape_key = old_show_only
|
||||
|
||||
def validate_meshes(meshes: List[Object]) -> Tuple[bool, str]:
|
||||
"""Validates a list of mesh objects to ensure they are suitable for joining operations"""
|
||||
if not meshes:
|
||||
return False, t("Optimization.no_meshes")
|
||||
if not all(mesh.data for mesh in meshes):
|
||||
return False, t("Optimization.invalid_mesh_data")
|
||||
if not all(mesh.type == 'MESH' for mesh in meshes):
|
||||
return False, t("Optimization.non_mesh_objects")
|
||||
return True, ""
|
||||
|
||||
def join_mesh_objects(context: Context, meshes: List[Object], progress: Optional[ProgressTracker] = None) -> Tuple[bool, str]:
|
||||
"""Combines multiple mesh objects into a single mesh with proper cleanup and UV fixing"""
|
||||
try:
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
for mesh in meshes:
|
||||
mesh.select_set(True)
|
||||
|
||||
if context.selected_objects:
|
||||
context.view_layer.objects.active = context.selected_objects[0]
|
||||
|
||||
if progress:
|
||||
progress.step(t("Optimization.joining_meshes"))
|
||||
bpy.ops.object.join()
|
||||
|
||||
if progress:
|
||||
progress.step(t("Optimization.applying_transforms"))
|
||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
||||
|
||||
if progress:
|
||||
progress.step(t("Optimization.fixing_uvs"))
|
||||
fix_uv_coordinates(context)
|
||||
|
||||
return True, t("Optimization.meshes_joined")
|
||||
|
||||
return False, t("Optimization.no_mesh_selected")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to join meshes: {str(e)}")
|
||||
return False, str(e)
|
||||
|
||||
def fix_uv_coordinates(context: Context) -> None:
|
||||
"""Normalizes and fixes UV coordinates for the active mesh object"""
|
||||
obj: Object = context.object
|
||||
current_mode: str = context.mode
|
||||
current_active: Object = context.view_layer.objects.active
|
||||
current_selected: List[Object] = context.selected_objects.copy()
|
||||
|
||||
try:
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
obj.select_set(True)
|
||||
context.view_layer.objects.active = obj
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
|
||||
with context.temp_override(active_object=obj):
|
||||
bpy.ops.uv.select_all(action='SELECT')
|
||||
bpy.ops.uv.average_islands_scale()
|
||||
|
||||
logger.debug(f"UV Fix - Successfully processed {obj.name}")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"UV Fix - Skipped processing for {obj.name}: {str(e)}")
|
||||
|
||||
finally:
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
for sel_obj in current_selected:
|
||||
sel_obj.select_set(True)
|
||||
context.view_layer.objects.active = current_active
|
||||
|
||||
def clear_unused_data_blocks(self) -> int:
|
||||
"""Removes all unused data blocks from the current Blender file"""
|
||||
initial_count: int = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) if isinstance(getattr(bpy.data, attr), bpy.types.bpy_prop_collection))
|
||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||
final_count: int = sum(len(getattr(bpy.data, attr)) for attr in dir(bpy.data) if isinstance(getattr(bpy.data, attr), bpy.types.bpy_prop_collection))
|
||||
return initial_count - final_count
|
||||
|
||||
+16
-3
@@ -14,7 +14,7 @@ from .logging_setup import logger
|
||||
from .translations import t, get_languages_list, update_language
|
||||
from .addon_preferences import get_preference, save_preference
|
||||
from .updater import get_version_list
|
||||
from .common import get_armature_list
|
||||
from .common import get_armature_list, get_active_armature, get_all_meshes
|
||||
|
||||
def update_validation_mode(self, context):
|
||||
logger.info(f"Updating validation mode to: {self.validation_mode}")
|
||||
@@ -38,7 +38,7 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
active_armature: EnumProperty(
|
||||
items=get_armature_list,
|
||||
name=t("QuickAccess.select_armature"),
|
||||
description=t("QuickAccess.select_armature")
|
||||
description=t("QuickAccess.select_armature"),
|
||||
)
|
||||
|
||||
language: EnumProperty(
|
||||
@@ -72,6 +72,20 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
default=False
|
||||
)
|
||||
|
||||
remove_doubles_merge_distance: FloatProperty(
|
||||
name=t("Optimization.merge_distance"),
|
||||
description=t("Optimization.merge_distance_desc"),
|
||||
default=0.0001,
|
||||
min=0.00001,
|
||||
max=0.1
|
||||
)
|
||||
|
||||
remove_doubles_advanced: BoolProperty(
|
||||
name=t("Optimization.remove_doubles_advanced"),
|
||||
description=t("Optimization.remove_doubles_advanced_desc"),
|
||||
default=False
|
||||
)
|
||||
|
||||
def register() -> None:
|
||||
"""Register the Avatar Toolkit property group"""
|
||||
logger.info("Registering Avatar Toolkit properties")
|
||||
@@ -83,4 +97,3 @@ def unregister() -> None:
|
||||
logger.info("Unregistering Avatar Toolkit properties")
|
||||
del bpy.types.Scene.avatar_toolkit
|
||||
logger.debug("Properties unregistered successfully")
|
||||
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ class AvatarToolkit_PT_UpdaterPanel(bpy.types.Panel):
|
||||
bl_region_type = 'UI'
|
||||
bl_category = CATEGORY_NAME
|
||||
bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
|
||||
bl_order = 1
|
||||
bl_order = 3
|
||||
|
||||
def draw(self, context: bpy.types.Context) -> None:
|
||||
layout = self.layout
|
||||
|
||||
Reference in New Issue
Block a user