5.5 KiB
技术设计:Cesium 材质导出契约化
对应
prd.md。本文件定义边界、数据流、兼容策略和风险控制。
1. 当前边界
catalog.py 是纯 Python 层,只声明材质事实,不能 import bpy。materials.py
属于 bpy 层,负责把 catalog spec 变成真实 bpy.types.Material。export_cesium.py
打开 .blend 后只应消费场景里已有的材质信息。
因此正确边界是:
catalog.MATERIALS[*]["cesium"] # 纯数据
│
▼
materials.from_spec() # bpy 层写 material["cesium_export"]
│
▼
<area>.blend # 契约随场景文件保存
│
▼
export_cesium.py # 优先读 material custom property
不采用:
export_cesium.py -> import catalog -> 按 material.name 反查
原因:这仍然依赖材质名字符串,而且旧 .blend 应该能在没有新 catalog contract 的情况下导出。
2. Contract Shape
材质自定义属性名固定为:
CESIUM_EXPORT_PROPERTY = "cesium_export"
JSON payload 建议 shape:
{
"tint": [[0.92, 0.94, 0.92], 0.38],
"metallic": 0.0,
"base_color": [0.93, 0.94, 0.91],
"emission": [[0.93, 0.94, 0.91], 0.18]
}
字段语义:
| 字段 | 类型 | 语义 | 旧来源 |
|---|---|---|---|
tint |
[[r,g,b], factor] |
diffuse 贴图导出前往目标颜色混合 | EXPORT_TINTS |
metallic |
number | 覆盖导出 PBR metallic | EXPORT_METALLIC_OVERRIDES |
base_color |
[r,g,b] |
直接覆盖导出材质 base color,并禁用 diffuse/normal 图 | EXPORT_BASE_COLOR_OVERRIDES |
emission |
[[r,g,b], strength] |
设置导出材质自发光 | EXPORT_EMISSION_OVERRIDES |
缺失字段表示沿用源材质当前值或当前特殊路径。
3. Catalog Migration
把四张旧表中的有效条目迁入 catalog.MATERIALS 对应项:
Grass->MATERIALS["grass"]["cesium"]Scrub Ground Cover->MATERIALS["scrub"]["cesium"]Tree Crown*-> 现有tree_crown*["cesium"]扩展到完整字段Office White Plaster Facade->building_defaultOffice Light Flat Roof->building_office_roofIndustrial White Ribbed Facade->building_industrialFactory Blue Metal Roof->building_industrial_roof
Office White Metal Facade 当前没有 catalog 材质,不迁入新契约。旧表可保留该 key 作为旧
.blend 回退兼容。
catalog.CESIUM_EXPORT 应消失或变成真实消费路径。优先方案:删除全局 CESIUM_EXPORT,
把其中仍有效的内容迁入各自 MATERIALS[*]["cesium"]。
4. Material Construction
在 materials.py:
- import
json - 定义同名常量
CESIUM_EXPORT_PROPERTY = "cesium_export",或一个私有 helper from_spec(spec)构造材质后调用:
def apply_cesium_contract(material, spec):
contract = spec.get("cesium")
if contract is None:
material.pop(CESIUM_EXPORT_PROPERTY, None)
return
material[CESIUM_EXPORT_PROPERTY] = json.dumps(contract, sort_keys=True)
注意:
sort_keys=True让.blend摘要更稳定。- 没有
cesium的材质应清掉旧属性,避免同名材质复用时残留。 catalog.py仍不 importbpy。
5. Export Consumption
在 export_cesium.py:
- 增加
cesium_contract(material),读取并json.loads(material.get("cesium_export", "{}")) - JSON 解析失败时返回
{}并继续旧回退,避免坏旧文件直接崩溃 make_export_material(material)开头读取一次 contract:
contract = cesium_contract(material)
- 每个覆盖点改成 “contract 优先,旧表回退”:
base_color = contract.get("base_color", EXPORT_BASE_COLOR_OVERRIDES.get(material.name, source_color(material)))
metallic = contract.get("metallic", EXPORT_METALLIC_OVERRIDES.get(...))
emission = contract.get("emission", EXPORT_EMISSION_OVERRIDES.get(material.name))
tint = contract.get("tint", EXPORT_TINTS.get(material.name))
cesium_tinted_image()可以改为接收tint参数,避免函数内部再查旧表。
6. Foliage Special Case
Alpha cut-out foliage 不在本次 contract 化范围内,原因是它不只是普通材质覆盖,还包含:
source_alpha_clipped(material)alpha_dilated_image(..., gain=FOLIAGE_ALBEDO_GAIN, saturation=FOLIAGE_SATURATION)- diffuse texture 连接到 emission color
FOLIAGE_EMISSION
这些逻辑保持原样。普通 contract 的 emission 只处理非 alpha-clipped 或程序化材质的平铺
emission override;alpha-clipped 分支仍使用 diffuse-as-emissive texture。
7. Validation Strategy
快速检查:
python3 -m unittest discover blender/tests
结构验证:
node scripts/parity.js capture material-contract-before
node scripts/parity.js capture material-contract-after
node scripts/parity.js compare material-contract-before material-contract-after
如果 before capture 已存在于实现前,after 在实现后跑。若 compare 报差异:
.blend摘要多出材质自定义属性cesium_export是预期差异,但需要确认没有对象、网格、 材质槽顺序、GLB material PBR 参数等非预期变化。- GLB 摘要应尽量全绿;若发生 PBR 参数变化,优先修实现而不是接受差异。
8. Rollback
回滚点明确:
catalog.py还原MATERIALS["cesium"]迁移和CESIUM_EXPORT处理。materials.py删除 custom property 写入。export_cesium.py恢复旧四张表直接读取。- spec 更新随代码回滚。