chore(task): archive 08-03-material-export-contract
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# 技术设计: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
|
||||
|
||||
材质自定义属性名固定为:
|
||||
|
||||
```python
|
||||
CESIUM_EXPORT_PROPERTY = "cesium_export"
|
||||
```
|
||||
|
||||
JSON payload 建议 shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"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_default`
|
||||
- `Office Light Flat Roof` -> `building_office_roof`
|
||||
- `Industrial White Ribbed Facade` -> `building_industrial`
|
||||
- `Factory 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`:
|
||||
|
||||
1. import `json`
|
||||
2. 定义同名常量 `CESIUM_EXPORT_PROPERTY = "cesium_export"`,或一个私有 helper
|
||||
3. `from_spec(spec)` 构造材质后调用:
|
||||
|
||||
```python
|
||||
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` 仍不 import `bpy`。
|
||||
|
||||
## 5. Export Consumption
|
||||
|
||||
在 `export_cesium.py`:
|
||||
|
||||
1. 增加 `cesium_contract(material)`,读取并 `json.loads(material.get("cesium_export", "{}"))`
|
||||
2. JSON 解析失败时返回 `{}` 并继续旧回退,避免坏旧文件直接崩溃
|
||||
3. `make_export_material(material)` 开头读取一次 contract:
|
||||
|
||||
```python
|
||||
contract = cesium_contract(material)
|
||||
```
|
||||
|
||||
4. 每个覆盖点改成 “contract 优先,旧表回退”:
|
||||
|
||||
```python
|
||||
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))
|
||||
```
|
||||
|
||||
5. `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
|
||||
|
||||
快速检查:
|
||||
|
||||
```bash
|
||||
python3 -m unittest discover blender/tests
|
||||
```
|
||||
|
||||
结构验证:
|
||||
|
||||
```bash
|
||||
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 更新随代码回滚。
|
||||
Reference in New Issue
Block a user