diff --git a/Tools/ModelTranslator/bl_decimate.py b/Tools/ModelTranslator/bl_decimate.py index 11b8e753..21a309e0 100644 --- a/Tools/ModelTranslator/bl_decimate.py +++ b/Tools/ModelTranslator/bl_decimate.py @@ -1,5 +1,5 @@ """Blender 内运行:FBX 减面到指定三角面数 + UV 重展(锐边 seam 或 Smart UV Project)。 -调用:blender -b --factory-startup --python bl_decimate.py -- [seam|smart] +调用:blender -b --factory-startup --python bl_decimate.py -- [seam|smart|none] """ import os import sys @@ -28,6 +28,11 @@ UV_FLIP_TOL = 0.02 # 质量门:UV 翻转面占比超此值回退 smart_pr UV_OVERLAP_TOL = 0.08 # 质量门:UV 重叠面占比阈值(手工 UV 同口径约 5%,灾难性失败 >20%) +def uv_gate_ok(flipped, overlap): + """UV 质量门:翻转与重叠占比都在阈值内。overlap 为 None(op 不可用)按 0 处理。""" + return flipped <= UV_FLIP_TOL and (overlap or 0.0) <= UV_OVERLAP_TOL + + def count_islands(n_faces, adjacent_pairs): """union-find 数 UV 岛:n_faces 个面,adjacent_pairs 为 UV 连续的面索引对。""" parent = list(range(n_faces)) @@ -199,8 +204,7 @@ def _do_unwrap(obj, mode, warnings): if mode == "seam": _unwrap_seam(obj, warnings) m = _collect_uv_metrics(obj) - overlap = m["overlap"] or 0.0 - if m["flipped"] <= UV_FLIP_TOL and overlap <= UV_OVERLAP_TOL: + if uv_gate_ok(m["flipped"], m["overlap"]): m["mode"] = "seam" return m warnings.append("seam 展开质量不达标(翻转 %.1f%% 重叠 %s),回退 smart_project" @@ -250,7 +254,13 @@ def main(): if not within_tolerance(target, cur) and cur > target: warnings.append("修正 %d 轮后仍超差:%d 面(目标 %d ±3%%)" % (MAX_RETRY, cur, target)) - uv_info = _do_unwrap(obj, unwrap_mode, warnings) + if unwrap_mode == "none": + # rizom 管线:跳过展开,UV 由后续 RizomUV 步骤生成 + _clear_uv_layers(obj.data) + uv_info = {"mode": "none", "islands": 0, "fill": 0.0, + "flipped": 0.0, "overlap": None} + else: + uv_info = _do_unwrap(obj, unwrap_mode, warnings) out_dir = os.path.dirname(os.path.abspath(out_fbx)) os.makedirs(out_dir, exist_ok=True) # 仅导出合并后的对象;整场景导出会把 armature/empty 等非 mesh 带进 _low.fbx diff --git a/Tools/ModelTranslator/tests/test_bl_decimate.py b/Tools/ModelTranslator/tests/test_bl_decimate.py index 91269446..c73ca1bb 100644 --- a/Tools/ModelTranslator/tests/test_bl_decimate.py +++ b/Tools/ModelTranslator/tests/test_bl_decimate.py @@ -75,5 +75,22 @@ class TestFillRatio(unittest.TestCase): self.assertEqual(bd.fill_ratio([]), 0.0) +class TestUvGateOk(unittest.TestCase): + def test_clean_passes(self): + self.assertTrue(bd.uv_gate_ok(0.0, 0.0)) + + def test_boundary_passes(self): + self.assertTrue(bd.uv_gate_ok(bd.UV_FLIP_TOL, bd.UV_OVERLAP_TOL)) + + def test_flip_exceeds_fails(self): + self.assertFalse(bd.uv_gate_ok(0.03, 0.0)) + + def test_overlap_exceeds_fails(self): + self.assertFalse(bd.uv_gate_ok(0.0, 0.09)) + + def test_overlap_none_treated_as_zero(self): + self.assertTrue(bd.uv_gate_ok(0.01, None)) + + if __name__ == "__main__": unittest.main()