Merge pull request #155 from 989onan/patch-1

Add Explode Model
This commit is contained in:
Yusarina
2025-04-10 12:29:36 +01:00
committed by GitHub
3 changed files with 102 additions and 2 deletions
+94 -1
View File
@@ -1,7 +1,7 @@
import bpy import bpy
import numpy as np import numpy as np
from bpy.types import Operator, Context from bpy.types import Operator, Context
from typing import Set from typing import Set, Literal
from ...core.translations import t from ...core.translations import t
from ...core.logging_setup import logger from ...core.logging_setup import logger
from ...core.common import get_active_armature, get_all_meshes from ...core.common import get_active_armature, get_all_meshes
@@ -99,3 +99,96 @@ class AvatarToolkit_OT_SelectShortestSeamPath(Operator):
return {'FINISHED'} return {'FINISHED'}
class AvatarToolkit_OT_ExplodeMesh(Operator):
"""Explodes the mesh for use with painting programs, or painting inside blender."""
bl_idname = "avatar_toolkit.explode_mesh"
bl_label = t("Tools.explode_mesh")
bl_description = t("Tools.explode_mesh_desc")
bl_options = {'REGISTER', 'UNDO'}
distance: bpy.props.FloatProperty(default=2.0,name=t("Tools.explode_mesh.distance"),description=t("Tools.explode_mesh.distance_desc"))
split_on_seams: bpy.props.BoolProperty(default=True,name=t("Tools.explode_mesh.split_on_seams"),description=t("Tools.explode_mesh.split_on_seams_desc"))
def draw(self, context: Context) -> None:
"""Draw the operator's UI"""
layout = self.layout
layout.prop(self, "distance")
def invoke(self, context: Context, event: bpy.types.Event) -> set[str]:
"""Initialize the operator"""
return context.window_manager.invoke_props_dialog(self)
@classmethod
def poll(cls, context: Context) -> bool:
return context.view_layer.objects.active.type == "MESH" and len(context.view_layer.objects.selected) == 1
def execute(self, context: Context) -> Set[str]:
mesh_obj: bpy.types.Object = context.view_layer.objects.active.type
mesh: bpy.types.Mesh = context.view_layer.objects.active.data
if(self.split_on_seams):
#set to correct mode
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='EDGE')
#mark seams by islands
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.uv.select_all(action="SELECT")
bpy.ops.uv.seams_from_islands(mark_seams=True,mark_sharp=False)
#clear selection
bpy.ops.mesh.select_all(action="DESELECT")
bpy.ops.object.mode_set(mode='OBJECT')
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(mesh) # fill it in from active mesh
#select seam edges
for idx,edge in enumerate(bm.edges):
edge.select = edge.seam
bm.to_mesh(mesh)
bm.free()
#split edges.
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.edge_split()
#separate by loose.
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='FACE')
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.mesh.separate(type='LOOSE')
distance: float = self.distance
#set origins to geometry
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.origin_set(type="ORIGIN_GEOMETRY",center="BOUNDS")
#store original settings
origin_only_orig: bool = context.scene.tool_settings.use_transform_data_origin
pos_only_orig: bool = context.scene.tool_settings.use_transform_pivot_point_align
parents_only_orig: bool = context.scene.tool_settings.use_transform_skip_children
original_pivot: Literal['BOUNDING_BOX_CENTER', 'CURSOR', 'INDIVIDUAL_ORIGINS', 'MEDIAN_POINT', 'ACTIVE_ELEMENT'] = context.scene.tool_settings.transform_pivot_point
#set scene settings correctly.
context.scene.tool_settings.use_transform_data_origin = False
context.scene.tool_settings.use_transform_pivot_point_align = True
context.scene.tool_settings.use_transform_skip_children = False
context.scene.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
#spread out separated objects
bpy.ops.transform.resize(value=(self.distance, self.distance, self.distance), orient_type='GLOBAL')
#restore settings.
context.scene.tool_settings.use_transform_data_origin = origin_only_orig
context.scene.tool_settings.use_transform_pivot_point_align = pos_only_orig
context.scene.tool_settings.use_transform_skip_children = parents_only_orig
context.scene.tool_settings.transform_pivot_point = original_pivot
return {'FINISHED'}
+6
View File
@@ -215,6 +215,12 @@
"Tools.clean_weights_threshold_desc": "Minimum weight value to consider a bone as weighted", "Tools.clean_weights_threshold_desc": "Minimum weight value to consider a bone as weighted",
"Tools.find_shortest_seam_path": "Find Shortest Seam Path", "Tools.find_shortest_seam_path": "Find Shortest Seam Path",
"Tools.find_shortest_seam_path_desc": "Find shortest path of seams between two selected vertices connected to seams.", "Tools.find_shortest_seam_path_desc": "Find shortest path of seams between two selected vertices connected to seams.",
"Tools.explode_mesh":"Explode Mesh for Painting",
"Tools.explode_mesh_desc": "Explodes the mesh for use with painting programs, or painting inside blender.",
"Tools.explode_mesh.distance": "Distance",
"Tools.explode_mesh.distance_desc": "Scale factor for distance between exploded items on model.",
"Tools.explode_mesh.split_on_seams_desc":"Split model on UV seams to separate islands from each other.",
"Tools.explode_mesh.split_on_seams":"Split on Seams",
"Tools.apply_modifier_on_shapekey_obj":"Apply Modifier on Shapekey Object", "Tools.apply_modifier_on_shapekey_obj":"Apply Modifier on Shapekey Object",
"Tools.apply_modifier_on_shapekey_obj_desc":"Applies a modifier on an object regardless of it having shapekeys.", "Tools.apply_modifier_on_shapekey_obj_desc":"Applies a modifier on an object regardless of it having shapekeys.",
"Tools.merge_title": "Merge Tools", "Tools.merge_title": "Merge Tools",
+2 -1
View File
@@ -18,7 +18,7 @@ from ..functions.tools.bone_tools import (
from ..functions.tools.standardize_armature import AvatarToolkit_OT_StandardizeArmature from ..functions.tools.standardize_armature import AvatarToolkit_OT_StandardizeArmature
from ..functions.tools.merge_tools import AvatarToolkit_OT_MergeToActive, AvatarToolkit_OT_MergeToParent, AvatarToolkit_OT_ConnectBones from ..functions.tools.merge_tools import AvatarToolkit_OT_MergeToActive, AvatarToolkit_OT_MergeToParent, AvatarToolkit_OT_ConnectBones
from ..functions.tools.rigify_converter import AvatarToolkit_OT_ConvertRigifyToUnity from ..functions.tools.rigify_converter import AvatarToolkit_OT_ConvertRigifyToUnity
from ..functions.tools.general_mesh_tools import AvatarToolkit_OT_SelectShortestSeamPath from ..functions.tools.general_mesh_tools import AvatarToolkit_OT_SelectShortestSeamPath, AvatarToolkit_OT_ExplodeMesh
from ..functions.custom_tools.force_apply_modifier import AvatarToolkit_OT_ApplyModifierForShapkeyObj from ..functions.custom_tools.force_apply_modifier import AvatarToolkit_OT_ApplyModifierForShapkeyObj
class AvatarToolKit_PT_ToolsPanel(Panel): class AvatarToolKit_PT_ToolsPanel(Panel):
@@ -68,6 +68,7 @@ class AvatarToolKit_PT_ToolsPanel(Panel):
col.separator(factor=0.5) col.separator(factor=0.5)
col.operator(AvatarToolkit_OT_SelectShortestSeamPath.bl_idname,text=t("Tools.find_shortest_seam_path"),icon="MESH_DATA") col.operator(AvatarToolkit_OT_SelectShortestSeamPath.bl_idname,text=t("Tools.find_shortest_seam_path"),icon="MESH_DATA")
col.operator(AvatarToolkit_OT_ApplyModifierForShapkeyObj.bl_idname,text=t("Tools.apply_modifier_on_shapekey_obj"),icon="SHAPEKEY_DATA") col.operator(AvatarToolkit_OT_ApplyModifierForShapkeyObj.bl_idname,text=t("Tools.apply_modifier_on_shapekey_obj"),icon="SHAPEKEY_DATA")
col.operator(AvatarToolkit_OT_ExplodeMesh.bl_idname,text=t("Tools.explode_mesh"),icon="MOD_EXPLODE")
# Standardization Tools # Standardization Tools