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
This commit is contained in:
88
editor/body_mesh/utils.py
Normal file
88
editor/body_mesh/utils.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user