Files
AIC-Project/docs/superpowers/specs/2026-07-15-model-translator-design.md
2026-07-15 10:43:01 +08:00

4.5 KiB
Raw Permalink Blame History

ModelTranslator 工具设计文档

日期:2026-07-15 状态:已确认

目标

Tools/ModelTranslator/ 下的 Python 工具:用 headless Blender 把带 PBR 贴图的 FBX(如 src/tong.fbx)转换为:

  1. 纯模型 FBX(剥离贴图,保留材质名/槽位)
  2. XPbr shader 所需贴图(每材质一套,≤2048×2048):
    • 基础贴图:RGB=颜色,A=透明 > AO > 255(自动判定)
    • 混合贴图:RG=球面编码法线,B=金属度,A=粗糙度
  3. Unity 开箱即用资产:贴图/材质/FBX 的 .meta.mat 全部预生成,拷入 Client/Assets/ 即可直接使用

环境

  • BlenderD:\tools\blender-5.0.0-windows-x64\blender.exe5.0),查找顺序:--blender 参数 → 环境变量 BLENDER_EXE → 上述默认路径 → PATH
  • 外层 CLI 用系统 Python 3.12;图像处理在 Blender 内用 bpy + 自带 numpy,不引第三方依赖

文件结构

Tools/ModelTranslator/
  model_translator.py   # CLI 入口:找 blender、组命令行、汇报结果
  bl_convert.py         # Blender 内运行的转换脚本
  README.md             # 用法说明
  src/                  # 源 FBX(已存在)
  out/<模型名>/         # 输出(git 忽略)

CLI

python model_translator.py src/tong.fbx        # 单文件
python model_translator.py src/                # 目录批量(*.fbx
  [-o out] [--max-size 2048] [--blender <exe>]

bl_convert.py 流程(每个 FBX

  1. 空场景导入 FBX,解包全部内嵌贴图
  2. 逐材质找 Principled BSDF,沿连线识别贴图:Base Color、Alpha、Normal(穿过 Normal Map 节点)、Metallic、RoughnessAO 按贴图名匹配(含 ao/occlusion/ambient,不区分大小写)
  3. 目标尺寸 = min(max-size, 各源贴图最大边),所有参与贴图缩放到统一尺寸(image.scale()
  4. 基础贴图:RGB=颜色贴图(无则 Principled 常量色);A=透明贴图 > AO 贴图 > 255
  5. 混合贴图:
    • RG=法线球面编码:切线法线 n = rgb*2-1 归一化后 enc = n.xy/√(2(1+n.z)) × 0.5 + 0.5;无法线贴图填 (0.5, 0.5)
    • B=金属度贴图(取 R 通道)或 Principled 常量
    • A=粗糙度贴图(取 R 通道)或 Principled 常量
  6. 保存 RGBA PNG 到 out/<模型名>/
  7. 删除材质中所有贴图节点,path_mode='NONE' 导出纯模型 FBX
  8. 打印 JSON 摘要(stdout 标记行),runner 转为可读日志

Unity 资产生成(model_translator.py 内完成,纯文本模板)

每材质:

文件 要点
<模型>_<材质>_base.png.meta TextureImportersRGB 开,maxTextureSize 2048
<模型>_<材质>_mix.png.meta TextureImportersRGB 关(线性),maxTextureSize 2048
<模型>_<材质>.mat shader 引用 XPbr GUID(见下);_MainTex/_MixTex 引用预分配贴图 GUID;透明模式时写 keyword _ALPHATEST_ON_AlphaTest=1_Metallic/_Roughness/_AO=1.0
<模型>_<材质>.mat.meta NativeFormatImportermainObjectFileID 2100000
  • XPbr shader GUIDcab897163f45445fa34263d6670bfc9eClient/Assets/Game/shader/XShader/XPbr.shader.meta,若该 meta 变更需同步工具常量)
  • 模型 FBX 生成 .metaModelImporter):externalObjects 按材质名重映射到生成的 .mat GUID,模型拖进场景直接生效
  • 所有 GUID 用 uuid4().hex 预分配;同一模型重复转换时复用已存在 meta 里的 GUID(避免拷入 Unity 后再次转换导致引用断裂)

配套 shader 修改

Client/Assets/Game/shader/XShader/XPbr_Base.hlslDecodeSphereMap 入口加 encoded = encoded * 2 - 1;:现编码只能表示 xy≥0 的法线(无符号 rg),重映射后可表示全半球。只影响 XPbr(无存量资源),不动 XTex。

错误处理

  • 找不到 Blender → 明确报错并提示 --blender
  • 材质无 Principled BSDF → 警告,用全常量兜底(灰色、平面法线、金属 0、粗糙 0.5)
  • 贴图输入是程序纹理/复杂节点 → 警告,用该输入的默认常量
  • Blender 退出码非 0 → runner 透传 stderr 摘要

不做(YAGNI

合并图集/UV 重排、Cycles 烘焙、法线绿通道翻转选项(README 说明现状)、动画/骨骼处理(FBX 原样导出)。

验证

  1. 实跑 src/tong.fbxsrc/woodcar.fbx
  2. 输出文件齐全,贴图尺寸 ≤2048
  3. 法线 round-trip 校验:按 shader 公式解码生成贴图的 RG,与源法线角度误差 < 2°
  4. 拷入 Unity 工程验证材质/模型开箱可用(人工步骤)