Files
blender-vrm/editor/body_mesh/panel.py
小煜 d70b36fd75 feat(body_mesh): Add body mesh separator module with edge dissolution
- Add body_mesh submodule with VRM_OT_separate_non_skin_faces operator
- Add VRM_PT_body_mesh_separator panel for UI integration
- Add utility functions for mesh operations and edge dissolution logic
- Add comprehensive edge dissolution configuration files for all body parts (head, torso, arms, legs, hands) with UV coordinates
- Add test utilities for validating mesh separation operations
- Add .gitignore to exclude Python cache files and test artifacts
- Register body_mesh module in editor package initialization
- Update registration.py to include new body mesh components
2026-01-01 22:20:31 +08:00

114 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
from collections.abc import Set as AbstractSet
from typing import TYPE_CHECKING, Optional
from bpy.types import Context, Panel
from .utils import (
MaterialInfo,
find_body_mesh,
get_material_face_count,
is_skin_material,
)
if TYPE_CHECKING:
from bpy.types import Object
class VRM_PT_body_mesh_separator(Panel):
"""Body网格分离面板"""
bl_idname = "VRM_PT_body_mesh_separator"
bl_label = "Body Mesh Separator"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "VRM"
bl_options: AbstractSet[str] = set()
@classmethod
def poll(cls, context: Context) -> bool:
"""检查是否应该显示面板 - 仅在选中包含Body网格的Armature时显示"""
armature = cls._get_armature(context)
if armature is None:
return False
body_mesh = find_body_mesh(armature)
return body_mesh is not None
@classmethod
def _get_armature(cls, context: Context) -> Optional["Object"]:
"""获取当前选中的Armature对象"""
active_object = context.active_object
if active_object is None:
return None
if active_object.type == "ARMATURE":
return active_object
# 如果选中的是网格检查其父对象是否为Armature
if active_object.parent is not None and active_object.parent.type == "ARMATURE":
return active_object.parent
return None
def draw(self, context: Context) -> None:
"""绘制面板UI"""
layout = self.layout
armature = self._get_armature(context)
if armature is None:
layout.label(text="未找到Armature对象", icon="ERROR")
return
body_mesh = find_body_mesh(armature)
if body_mesh is None:
layout.label(text="未找到Body网格对象", icon="ERROR")
return
mesh_data = body_mesh.data
if mesh_data is None:
layout.label(text="Body网格数据无效", icon="ERROR")
return
# 显示材质统计信息
box = layout.box()
box.label(text="材质列表", icon="MATERIAL")
# 收集材质信息
materials_info: list[MaterialInfo] = []
for i, material in enumerate(mesh_data.materials):
if material is not None:
face_count = get_material_face_count(mesh_data, i)
is_skin = is_skin_material(material.name)
materials_info.append(
MaterialInfo(
name=material.name,
index=i,
face_count=face_count,
is_skin=is_skin,
)
)
# 显示材质列表
has_non_skin = False
for mat_info in materials_info:
row = box.row()
if mat_info.is_skin:
row.label(text=f"[皮肤] {mat_info.name}", icon="CHECKMARK")
else:
row.label(text=f"[非皮肤] {mat_info.name}", icon="MESH_DATA")
has_non_skin = True
row.label(text=f"{mat_info.face_count}")
# 显示分离操作按钮
layout.separator()
col = layout.column()
col.enabled = has_non_skin
col.operator(
"vrm.separate_non_skin_faces",
text="分离非皮肤面",
icon="MESH_DATA",
)
if not has_non_skin:
layout.label(text="没有非皮肤材质可分离", icon="INFO")