"""Blender 内运行:FBX -> 纯模型 FBX + XPbr 基础/混合贴图。 调用:blender -b --factory-startup --python bl_convert.py -- """ import numpy as np def encode_normal_rg(n): """切线法线 (N,3) -> 球面编码 (N,2),范围 [0,1]。 shader 侧 XPbr_Base.hlsl DecodeSphereMap 先 *2-1 再解码。""" n = n / np.maximum(np.linalg.norm(n, axis=-1, keepdims=True), 1e-8) z = np.clip(n[..., 2], -0.99, 1.0) denom = np.sqrt(2.0 * (1.0 + z)) enc = n[..., :2] / denom[..., None] return np.clip(enc * 0.5 + 0.5, 0.0, 1.0) def decode_sphere_map(enc01): """shader DecodeSphereMap 的 numpy 等价(含 *2-1),仅测试用。""" e = enc01 * 2.0 - 1.0 l = 1.0 - e[..., 0] ** 2 - e[..., 1] ** 2 l = np.clip(l, 0.0, 1.0) xy = e * np.sqrt(l)[..., None] return np.concatenate([xy * 2.0, (l * 2.0 - 1.0)[..., None]], axis=-1)