From 8ede09f859123f21ff9617f108ba5d4f406cdd7e Mon Sep 17 00:00:00 2001 From: ud18010 Date: Thu, 16 Jul 2026 10:36:01 +0800 Subject: [PATCH] =?UTF-8?q?ModelTranslator:=20=E5=87=8F=E9=9D=A2=20ratio/?= =?UTF-8?q?=E5=AE=B9=E5=B7=AE=E7=BA=AF=E9=80=BB=E8=BE=91=EF=BC=88TDD?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tools/ModelTranslator/bl_decimate.py | 24 +++++++++++ .../ModelTranslator/tests/test_bl_decimate.py | 40 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 Tools/ModelTranslator/bl_decimate.py create mode 100644 Tools/ModelTranslator/tests/test_bl_decimate.py diff --git a/Tools/ModelTranslator/bl_decimate.py b/Tools/ModelTranslator/bl_decimate.py new file mode 100644 index 00000000..e2d0df12 --- /dev/null +++ b/Tools/ModelTranslator/bl_decimate.py @@ -0,0 +1,24 @@ +"""Blender 内运行:FBX 减面到指定三角面数 + Smart UV 重展。 +调用:blender -b --factory-startup --python bl_decimate.py -- +""" +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +TOLERANCE = 0.03 # 面数相对误差容忍 +MAX_RETRY = 2 # ratio 修正轮数上限 + + +def decimate_ratio(target, cur): + """Decimate collapse ratio;cur <= target 或非法时返回 1.0(不减面)。""" + if cur <= 0 or cur <= target: + return 1.0 + return target / float(cur) + + +def within_tolerance(target, actual, tol=TOLERANCE): + """减面结果是否落在目标 ±tol 内。""" + if target <= 0: + return False + return abs(actual - target) <= target * tol diff --git a/Tools/ModelTranslator/tests/test_bl_decimate.py b/Tools/ModelTranslator/tests/test_bl_decimate.py new file mode 100644 index 00000000..9c59ba8d --- /dev/null +++ b/Tools/ModelTranslator/tests/test_bl_decimate.py @@ -0,0 +1,40 @@ +import os +import sys +import unittest + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import bl_decimate as bd + + +class TestDecimateRatio(unittest.TestCase): + def test_normal_reduction(self): + self.assertAlmostEqual(bd.decimate_ratio(5000, 1500000), 5000 / 1500000.0) + + def test_current_below_target_returns_one(self): + self.assertEqual(bd.decimate_ratio(5000, 3000), 1.0) + + def test_current_equal_target_returns_one(self): + self.assertEqual(bd.decimate_ratio(5000, 5000), 1.0) + + def test_zero_current_returns_one(self): + self.assertEqual(bd.decimate_ratio(5000, 0), 1.0) + + +class TestWithinTolerance(unittest.TestCase): + def test_exact_hit(self): + self.assertTrue(bd.within_tolerance(5000, 5000)) + + def test_within_3_percent(self): + self.assertTrue(bd.within_tolerance(5000, 5150)) # +3% + self.assertTrue(bd.within_tolerance(5000, 4850)) # -3% + + def test_outside_3_percent(self): + self.assertFalse(bd.within_tolerance(5000, 5200)) + self.assertFalse(bd.within_tolerance(5000, 4700)) + + def test_zero_target_is_false(self): + self.assertFalse(bd.within_tolerance(0, 0)) + + +if __name__ == "__main__": + unittest.main()