feat: 添加VRM网格工具插件,支持网格分离和UV边融并功能
添加VRM网格工具插件,包含以下主要功能: - Body网格分离:将非皮肤材质面分离为独立对象 - UV边融并:根据预定义UV数据将三角面转换为四边面 - 提供独立面板和操作符,与VRM官方插件兼容 - 包含材质处理顺序和自动转换逻辑 - 添加JSON数据文件和工具函数
This commit is contained in:
134
panel.py
Normal file
134
panel.py
Normal file
@@ -0,0 +1,134 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# VRM Mesh Tools - UI Panel for mesh separation and UV edge merging
|
||||
|
||||
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,
|
||||
find_face_mesh,
|
||||
get_material_face_count,
|
||||
is_retained_material,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bpy.types import Object
|
||||
|
||||
|
||||
class VRM_TOOLS_PT_mesh_separator(Panel):
|
||||
"""VRM Mesh Tools 面板 - 提供网格分离和UV边融并功能"""
|
||||
|
||||
bl_idname = "VRM_TOOLS_PT_mesh_separator"
|
||||
bl_label = "VRM Mesh Tools"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "VRM Tools" # 独立的侧边栏分类
|
||||
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")
|
||||
|
||||
# 收集材质信息,使用is_retained_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_retained = is_retained_material(material.name)
|
||||
materials_info.append(
|
||||
MaterialInfo(
|
||||
name=material.name,
|
||||
index=i,
|
||||
face_count=face_count,
|
||||
is_skin=is_retained, # 使用is_skin字段存储保留状态
|
||||
)
|
||||
)
|
||||
|
||||
# 显示材质列表,区分保留材质(SKIN/HAIR)和可分离材质(CLOTH和其他)
|
||||
has_separable = False
|
||||
for mat_info in materials_info:
|
||||
row = box.row()
|
||||
if mat_info.is_skin: # is_skin字段现在表示是否为保留材质
|
||||
# 保留材质(SKIN/HAIR)标记为"[保留]"
|
||||
row.label(text=f"[保留] {mat_info.name}", icon="CHECKMARK")
|
||||
else:
|
||||
# 可分离材质(CLOTH和其他)标记为"[分离]"
|
||||
row.label(text=f"[分离] {mat_info.name}", icon="MESH_DATA")
|
||||
has_separable = True
|
||||
row.label(text=f"{mat_info.face_count} 面")
|
||||
|
||||
# 显示分离操作按钮
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.enabled = has_separable
|
||||
col.operator(
|
||||
"vrm_tools.separate_non_skin_faces",
|
||||
text="分离非皮肤面",
|
||||
icon="MESH_DATA",
|
||||
)
|
||||
|
||||
if not has_separable:
|
||||
layout.label(text="没有可分离材质", icon="INFO")
|
||||
|
||||
# 显示UV边融并按钮
|
||||
layout.separator()
|
||||
face_mesh = find_face_mesh(armature) if armature else None
|
||||
has_vrm_structure = body_mesh is not None and face_mesh is not None
|
||||
|
||||
col = layout.column()
|
||||
col.enabled = has_vrm_structure
|
||||
col.operator(
|
||||
"vrm_tools.merge_uv_edges",
|
||||
text="根据UV转四边面",
|
||||
icon="MOD_EDGESPLIT",
|
||||
)
|
||||
|
||||
if not has_vrm_structure:
|
||||
layout.label(text="需要Body和Face网格", icon="INFO")
|
||||
Reference in New Issue
Block a user