"""法线球面编码 round-trip 测试。运行: blender -b --factory-startup --python tests/bl_test_encode.py 成功打印 ENCODE_TEST_OK,失败非零退出。""" import os import sys import numpy as np sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from bl_convert import encode_normal_rg, decode_sphere_map def main(): rng = np.random.default_rng(7) # 随机切线空间法线(z>=0 半球),含边缘方向 n = rng.normal(size=(4096, 3)) n[:, 2] = np.abs(n[:, 2]) n /= np.linalg.norm(n, axis=1, keepdims=True) n = np.vstack([n, [[0, 0, 1], [1, 0, 0], [-1, 0, 0], [0, -1, 0], [0.707, -0.707, 0]]]) enc = encode_normal_rg(n) # (N,2) in [0,1] assert enc.min() >= 0.0 and enc.max() <= 1.0, "encode out of [0,1]" enc8 = np.round(enc * 255.0) / 255.0 # 模拟 8bit PNG 存储 dec = decode_sphere_map(enc8) # shader 同款公式 dec /= np.linalg.norm(dec, axis=1, keepdims=True) cos = np.clip(np.sum(n * dec, axis=1), -1.0, 1.0) max_err = np.degrees(np.arccos(cos)).max() assert max_err < 2.0, "max angle error %.3f deg >= 2" % max_err # 平面法线编码值应为 (0.5, 0.5) flat = encode_normal_rg(np.array([[0.0, 0.0, 1.0]])) assert np.allclose(flat, 0.5, atol=1e-6), "flat normal must encode to 0.5" print("ENCODE_TEST_OK max_err=%.4f deg" % max_err) try: main() except Exception as e: print("ENCODE_TEST_FAIL:", e) sys.exit(1)