ModelTranslator: 烘焙射线距离/命名/包围盒校验纯逻辑(TDD)
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
"""Blender 内运行:高低模 Cycles 烘焙,低模 UV 上出 normal/ao/color/metallic/roughness。
|
||||||
|
调用:blender -b --factory-startup --python bl_bake.py -- \
|
||||||
|
<high.fbx> <low.fbx> <outdir> <size> <ray_distance|auto> <samples>
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
DEFAULT_RAY_PCT = 0.02 # 自动射线距离 = 低模包围盒对角线 * 2%
|
||||||
|
BBOX_TOL = 0.10 # 高低模包围盒尺寸相对差警告阈值
|
||||||
|
|
||||||
|
# (输出名, bake type, EMIT 来源的 Principled 输入, 目标图颜色空间)
|
||||||
|
BAKE_PASSES = [
|
||||||
|
("normal", 'NORMAL', None, 'Non-Color'),
|
||||||
|
("ao", 'AO', None, 'Non-Color'),
|
||||||
|
("color", 'EMIT', 'Base Color', 'sRGB'),
|
||||||
|
("metallic", 'EMIT', 'Metallic', 'Non-Color'),
|
||||||
|
("roughness", 'EMIT', 'Roughness', 'Non-Color'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def estimate_ray_distance(bbox_dims, pct=DEFAULT_RAY_PCT):
|
||||||
|
"""低模包围盒尺寸 (dx,dy,dz) -> 射线距离 = 对角线长 * pct。"""
|
||||||
|
return math.sqrt(sum(d * d for d in bbox_dims)) * pct
|
||||||
|
|
||||||
|
|
||||||
|
def output_stem(low_name):
|
||||||
|
"""低模名去掉 _low 后缀作为输出前缀(对齐工具3纯网格贴图命名约定)。"""
|
||||||
|
return low_name[:-4] if low_name.endswith("_low") else low_name
|
||||||
|
|
||||||
|
|
||||||
|
def bbox_mismatch(high_dims, low_dims, tol=BBOX_TOL):
|
||||||
|
"""任一轴尺寸相对差超 tol 返回 True;接近 0 的轴忽略(平面模型)。"""
|
||||||
|
for h, l in zip(high_dims, low_dims):
|
||||||
|
m = max(abs(h), abs(l))
|
||||||
|
if m > 1e-9 and abs(h - l) / m > tol:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import math
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
import bl_bake as bb
|
||||||
|
|
||||||
|
|
||||||
|
class TestEstimateRayDistance(unittest.TestCase):
|
||||||
|
def test_two_percent_of_bbox_diagonal(self):
|
||||||
|
# 3-4-12 直角箱对角线 = 13
|
||||||
|
self.assertAlmostEqual(bb.estimate_ray_distance((3.0, 4.0, 12.0)), 0.26)
|
||||||
|
|
||||||
|
def test_custom_pct(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
bb.estimate_ray_distance((1.0, 0.0, 0.0), pct=0.5), 0.5)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOutputStem(unittest.TestCase):
|
||||||
|
def test_strips_low_suffix(self):
|
||||||
|
self.assertEqual(bb.output_stem("well1500_low"), "well1500")
|
||||||
|
|
||||||
|
def test_keeps_name_without_suffix(self):
|
||||||
|
self.assertEqual(bb.output_stem("well1500"), "well1500")
|
||||||
|
|
||||||
|
def test_only_strips_trailing_suffix(self):
|
||||||
|
self.assertEqual(bb.output_stem("low_poly_low"), "low_poly")
|
||||||
|
|
||||||
|
|
||||||
|
class TestBboxMismatch(unittest.TestCase):
|
||||||
|
def test_identical_ok(self):
|
||||||
|
self.assertFalse(bb.bbox_mismatch((1.0, 2.0, 3.0), (1.0, 2.0, 3.0)))
|
||||||
|
|
||||||
|
def test_within_10_percent_ok(self):
|
||||||
|
self.assertFalse(bb.bbox_mismatch((1.0, 2.0, 3.0), (1.05, 1.9, 3.2)))
|
||||||
|
|
||||||
|
def test_one_axis_exceeds(self):
|
||||||
|
self.assertTrue(bb.bbox_mismatch((1.0, 2.0, 3.0), (1.0, 2.0, 3.5)))
|
||||||
|
|
||||||
|
def test_zero_axis_ignored(self):
|
||||||
|
# 平面模型某轴为 0,不应误报
|
||||||
|
self.assertFalse(bb.bbox_mismatch((1.0, 0.0, 3.0), (1.0, 0.0, 3.0)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user