- 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
89 lines
1.9 KiB
Python
89 lines
1.9 KiB
Python
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
||
from dataclasses import dataclass
|
||
from typing import TYPE_CHECKING, Optional
|
||
|
||
if TYPE_CHECKING:
|
||
from bpy.types import Mesh, Object
|
||
|
||
|
||
@dataclass
|
||
class MaterialInfo:
|
||
"""材质信息数据类"""
|
||
name: str
|
||
index: int
|
||
face_count: int
|
||
is_skin: bool
|
||
|
||
|
||
def find_body_mesh(armature: "Object") -> Optional["Object"]:
|
||
"""
|
||
在Armature的子对象中查找名为"Body"的网格对象
|
||
|
||
Args:
|
||
armature: Armature对象
|
||
|
||
Returns:
|
||
Body网格对象,如果不存在则返回None
|
||
"""
|
||
if armature is None:
|
||
return None
|
||
|
||
for child in armature.children:
|
||
if child.type == "MESH" and child.name == "Body":
|
||
return child
|
||
|
||
return None
|
||
|
||
|
||
def is_skin_material(material_name: str) -> bool:
|
||
"""
|
||
判断材质是否为皮肤材质
|
||
|
||
Args:
|
||
material_name: 材质名称
|
||
|
||
Returns:
|
||
如果材质名包含"SKIN"则返回True(不区分大小写)
|
||
"""
|
||
return "SKIN" in material_name.upper()
|
||
|
||
|
||
def get_material_face_count(mesh: "Mesh", material_index: int) -> int:
|
||
"""
|
||
获取指定材质的面数量
|
||
|
||
Args:
|
||
mesh: 网格数据
|
||
material_index: 材质索引
|
||
|
||
Returns:
|
||
使用该材质的面数量
|
||
"""
|
||
count = 0
|
||
for polygon in mesh.polygons:
|
||
if polygon.material_index == material_index:
|
||
count += 1
|
||
return count
|
||
|
||
|
||
def generate_unique_name(base_name: str, existing_names: set[str]) -> str:
|
||
"""
|
||
生成唯一的对象名称
|
||
|
||
Args:
|
||
base_name: 基础名称
|
||
existing_names: 已存在的名称集合
|
||
|
||
Returns:
|
||
唯一的名称
|
||
"""
|
||
if base_name not in existing_names:
|
||
return base_name
|
||
|
||
suffix = 1
|
||
while True:
|
||
candidate = f"{base_name}.{suffix:03d}"
|
||
if candidate not in existing_names:
|
||
return candidate
|
||
suffix += 1
|