chore(task): archive 08-25-rc-p3-render-separation
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{"file":".trellis/spec/blender/module-structure.md","reason":"检查道路 adapter 与建筑/植被/水体模块的边界没有漂移。"}
|
||||
{"file":".trellis/spec/blender/testing.md","reason":"检查 Blender 结构摘要、纯 Python schema 测试和提权运行要求。"}
|
||||
{"file":".trellis/spec/pipeline/index.md","reason":"检查 compiler 输出与 Blender 消费的 manifest 数据流。"}
|
||||
{"file":".trellis/spec/guides/cross-layer-thinking-guide.md","reason":"检查三层契约、材质槽和 source 文件名一致性。"}
|
||||
{"file":".trellis/spec/guides/artifact-parity-guide.md","reason":"检查两个区域和 throwaway 图层验证后的产物差异。"}
|
||||
@@ -0,0 +1,61 @@
|
||||
# Phase 3:Manifest 驱动的道路渲染设计
|
||||
|
||||
## Boundary
|
||||
|
||||
道路编译器是图层事实源,输出 `<nativeRoadDir>/manifest.json`;Blender 是渲染适配器,读取 manifest 并用宿主 `catalog.MATERIALS` / `ROAD_LAYERS` 完成材质与高度映射。建筑、植被、水体、OSM legacy 图层不改变。
|
||||
|
||||
```
|
||||
compiler CLI
|
||||
-> native-road/manifest.json + 12 declared GeoJSON sources
|
||||
-> generate_scene.py
|
||||
-> osmassets/native_roads.py
|
||||
-> catalog material/z lookup
|
||||
-> roads.assemble_geojson_layer
|
||||
```
|
||||
|
||||
## Manifest v1.1
|
||||
|
||||
`manifest.json` 顶层包含 `contract: "native-road-package/v1.1"`、`areaId` 和 `layers`。`layers` 必须恰好声明编译器输出的 12 个 source:
|
||||
|
||||
- `road_surface`, `intersection_surface`, `sidewalk_surface`, `edge_lines`, `lane_separators`, `center_lines`, `crosswalks`, `vehicle_stop_lines`, `direction_arrows`, `turn_arrows`
|
||||
- `lane_centerlines`, `connectors`
|
||||
|
||||
每项字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "center_lines",
|
||||
"role": "marking",
|
||||
"materialLayer": "center_lines",
|
||||
"splitBy": {
|
||||
"prop": "color",
|
||||
"cases": [
|
||||
{"match": "white", "material": "native_center_line_white"},
|
||||
{"default": true, "material": "center_lines"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`role` 为 `surface` 或 `marking` 时必须有 `materialLayer`;`semantic` 不得有材质要求,Blender 必须跳过其 GeoJSON。`splitBy` 只支持精确属性匹配和一个 default 分支,避免把渲染表达式语言复制进编译器。
|
||||
|
||||
编译器在原子提升前校验:每个声明 source 都对应 `layers/<source>.geojson`,目录中没有未声明的 GeoJSON;manifest 自身必须是有效 JSON。新增 manifest 不改变已有文件内容。
|
||||
|
||||
## Blender Adapter
|
||||
|
||||
新建 `blender/osmassets/native_roads.py`,公开一个接收 `native_road_dir`, `projector`, `collection`, `road_mats`, `material_layers` 的装配函数。模块负责读取/校验 manifest、解析 split cases、调用既有 `roads.assemble_geojson_layer`;不拥有图层注册表、不创建材质、不维护场景总计数。
|
||||
|
||||
`generate_scene.py` 仅负责 native-road 目录存在性、catalog material lookup、调用 adapter 和合并 `road_counts`。删除 `catalog.NATIVE_ROAD_LAYERS`;保留 `catalog.ROAD_LAYERS` 作为宿主材质和 z 高度事实源。
|
||||
|
||||
未知 `materialLayer`、缺少 source 文件、重复/遗漏 source、非法 role 或非法 splitBy 必须抛出 `RuntimeError`,不能静默跳过。semantic 图层必须不读取 GeoJSON、不创建对象、不增加 road count。
|
||||
|
||||
## Compatibility and Rollback
|
||||
|
||||
编译器契约从 `native-road-package/v1` 增加到 `v1.1`;manifest 是 v1.1 的必需输出。Blender 不提供旧 manifest fallback,因为新消费边界必须尽早暴露旧 compiler;回滚时恢复 `NATIVE_ROAD_LAYERS` 内联分支即可。旧 v1 产物仍可由旧 compiler tag 生成,不被本阶段改写。
|
||||
|
||||
## Verification
|
||||
|
||||
- 两个支持区域的 native-road 文件 parity:除新增 `manifest.json` 外所有现有 hash、orderHash、bytes 不变。
|
||||
- Blender 结构摘要和预览图与 Phase 0 基线一致;完整 Blender/Metal 运行需提权。
|
||||
- 纯 Python schema/manifest 测试覆盖 12 source、semantic skip、splitBy white/yellow、未知材质、缺文件和额外文件。
|
||||
- throwaway `debug_probe.geojson` + manifest 实测:不改宿主代码即可生成 Blender 几何;验证后删除 probe 并再次跑 parity。
|
||||
@@ -0,0 +1,5 @@
|
||||
{"file":".trellis/spec/blender/module-structure.md","reason":"native_roads.py 必须遵守 osmassets 的 bpy 依赖边界和 roads adapter 责任。"}
|
||||
{"file":".trellis/spec/blender/testing.md","reason":"Blender 层以结构摘要/parity 为主要回归防线,纯 schema 逻辑需可用系统 Python 测试。"}
|
||||
{"file":".trellis/spec/pipeline/index.md","reason":"native-road manifest 是跨 compiler/Blender 的 pipeline 文件契约。"}
|
||||
{"file":".trellis/spec/guides/cross-layer-thinking-guide.md","reason":"改动同时触及 compiler JSON、Blender Python 和契约文档。"}
|
||||
{"file":".trellis/spec/guides/artifact-parity-guide.md","reason":"本阶段必须证明除新增 manifest 外渲染产物不变。"}
|
||||
@@ -0,0 +1,85 @@
|
||||
# Phase 3 执行计划
|
||||
|
||||
## Step 1 — 枚举现有分流逻辑(定 schema 之前)
|
||||
|
||||
- [x] 读 `blender/generate_scene.py:796-834` 全部道路分支
|
||||
- [x] 列出每个 `source` 的处理方式:直接渲染 / 按属性分流 / 跳过
|
||||
- [x] 已知分流:
|
||||
- `center_lines`:`color != "white"` → `center_lines` 材质;
|
||||
`color == "white"` → `native_center_line_white`
|
||||
- `lane_separators`:`color != "yellow"` → `lane_separators`;
|
||||
`color == "yellow"` → `native_lane_separator_yellow`
|
||||
- [x] 确认 `lane_centerlines` / `connectors` 确实未被消费(→ `role: "semantic"`)
|
||||
- [x] 产出 `research/native-layer-consumption-matrix.md`
|
||||
|
||||
**门槛**:manifest schema 能表达矩阵里的每一行,无"特例硬编码"残留。
|
||||
|
||||
## Step 2 — 定 manifest schema 并落契约
|
||||
|
||||
- [x] 按父任务 `design.md` §3.2 定稿 schema
|
||||
- [x] 写入编译器仓库契约文档,版本标为 `native-road-package/v1.1`
|
||||
- [x] 记录:v1.1 起 `manifest.json` 为必需输出
|
||||
|
||||
## Step 3 — 编译器侧:生成 manifest
|
||||
|
||||
- [x] 编译器内建立图层注册表(单一事实源),`compileGeometry` 的输出键与之对应
|
||||
- [x] 写 `manifest.json` 到 outDir
|
||||
- [x] 编译器自校验:manifest 声明的每个 `source` 都必须有对应 geojson 文件,
|
||||
反之亦然(缺一即报错,不静默)
|
||||
- [x] parity:此步只**新增** manifest.json,其余文件应逐字节不变;hanyang-block 不参与
|
||||
|
||||
```bash
|
||||
# 只应多出 manifest.json
|
||||
node scripts/road-parity.js --config config/areas/fengshu-er-road.json \
|
||||
--compare .../baseline/fengshu-er-road.json
|
||||
```
|
||||
|
||||
## Step 4 — Blender 侧:抽模块 + 读 manifest
|
||||
|
||||
- [x] 新建 `blender/osmassets/native_roads.py`
|
||||
- [x] 把 `generate_scene.py:796-834` 的道路分支迁入
|
||||
- [x] 改为读 manifest 遍历;`role == "semantic"` 跳过
|
||||
- [x] `splitBy` 通用化实现,替掉两处硬编码 lambda
|
||||
- [x] **加断言**:manifest 里的 `materialLayer` 若不在 `catalog.MATERIALS` /
|
||||
`ROAD_LAYERS` 中,直接 raise,不静默跳过(风险表第二条)
|
||||
- [x] 删除 `catalog.NATIVE_ROAD_LAYERS`
|
||||
- [x] `generate_scene.py` 只保留一行调用
|
||||
|
||||
## Step 5 — 验证
|
||||
|
||||
```bash
|
||||
# .blend 结构摘要对基线
|
||||
npm run build:area -- --config config/areas/fengshu-er-road.json
|
||||
# 走 artifact-parity-guide 的结构摘要比对
|
||||
|
||||
# 两个有效区域跑通(hanyang-block 为废案,不参与)
|
||||
for a in fengshu-er-road nantaizi-lake-innovation-valley; do
|
||||
npm run build:area -- --config config/areas/$a.json || echo "FAIL $a"
|
||||
done
|
||||
|
||||
# 建筑/植被/水体未被改动
|
||||
git diff --stat -- blender/osmassets/ | grep -vE "native_roads|catalog"
|
||||
```
|
||||
|
||||
- [x] 渲染预览图人工对照(结构摘要粒度不足的兜底)
|
||||
|
||||
## Step 6 — AC3.4 实测(可扩展性证明)
|
||||
|
||||
这一步是整个 Phase 3 的价值证明,不可跳过。
|
||||
|
||||
- [x] 编译器加一个 throwaway 图层 `debug_probe.geojson`(复用 road-surface 几何仅验证 wiring)
|
||||
+ manifest 声明 `role: "marking"`,复用现有材质槽
|
||||
- [x] **不改宿主任何代码**,跑 blender 阶段
|
||||
- [x] 确认 Blender 场景中出现该图层几何
|
||||
- [x] 截图/记录证据到任务 `research/`
|
||||
- [x] 回滚 throwaway 图层
|
||||
|
||||
## Review Gate
|
||||
|
||||
AC3.1–AC3.7 全绿,特别是 AC3.4 有实测证据。
|
||||
|
||||
## Rollback
|
||||
|
||||
- 恢复 `catalog.NATIVE_ROAD_LAYERS`,`generate_scene.py` 恢复内联分支
|
||||
- `manifest.json` 可保留输出(无消费方时无害)
|
||||
- 编译器侧图层注册表保留(它本身是改进)
|
||||
@@ -0,0 +1,90 @@
|
||||
# Phase 3:道路与建筑渲染分离
|
||||
|
||||
父任务:`.trellis/tasks/08-25-road-compiler-extraction/`
|
||||
技术设计:父任务 `design.md` §3(含 manifest 形状与 Blender 侧改造方案)
|
||||
|
||||
## Goal
|
||||
|
||||
让编译器自声明图层,Blender 改为读 manifest 而非硬编码表;
|
||||
道路渲染从 `generate_scene.py` 抽离为独立模块,建筑/植被/水体保持原位。
|
||||
|
||||
**这是全案价值最高的一步** —— 它把一张跨仓库重复的表变成生成物,
|
||||
使"编译器加图层忘了改宿主"这类静默错误在结构上不可能。
|
||||
|
||||
## 背景:当前的静默错误风险
|
||||
|
||||
`blender/osmassets/catalog.py:53` 的 `NATIVE_ROAD_LAYERS` 有 10 项,
|
||||
而编译器写 12 个 geojson —— `lane_centerlines` 与 `connectors` 是语义层不参与渲染。
|
||||
|
||||
**但这个事实只存在于这张表的省略里,编译器侧没有任何声明。**
|
||||
拆仓库之后,这张表和它描述的对象分处两个仓库,漂移只是时间问题。
|
||||
|
||||
`.trellis/spec/pipeline/index.md` 首页已经把图层表标为「最容易出静默错误」。
|
||||
|
||||
## Requirements
|
||||
|
||||
### R3.1 编译器输出 layer manifest
|
||||
|
||||
`<outDir>/manifest.json`,形状见父任务 `design.md` §3.2。要点:
|
||||
|
||||
- 每个图层声明 `source`(geojson 文件名)、`role`、以及渲染角色所需的 `materialLayer`
|
||||
- `role: "semantic"` 显式标记不渲染的图层 —— 把省略变成声明
|
||||
- `splitBy` 表达按属性分流到不同材质的逻辑
|
||||
(当前 `generate_scene.py:815-819` 硬编码的 `color != "white"` / `color == "yellow"`)
|
||||
- 材质本体(颜色、z 高度、贴图)**仍归宿主** `catalog.py::MATERIALS`;
|
||||
编译器不懂渲染,只声明"我有哪些图层、什么角色、该用哪个材质槽"
|
||||
|
||||
### R3.2 Blender 侧改造
|
||||
|
||||
- `generate_scene.py` 内道路分支抽为 `blender/osmassets/native_roads.py`
|
||||
- 新模块读 manifest 遍历,不再查硬编码表
|
||||
- 删除 `catalog.NATIVE_ROAD_LAYERS`
|
||||
- 建筑(`handle_building` / `dispatch_ways`)、植被、水体**保持原位不动**
|
||||
|
||||
### R3.3 契约版本处理
|
||||
|
||||
新增 `manifest.json` 是**向后兼容的增量**(旧消费方忽略未知文件即可),
|
||||
但 Blender 改为依赖它之后就成了必需项。
|
||||
|
||||
- 契约文档记录:`manifest.json` 自 v1.1 起为必需输出
|
||||
- 宿主声明所需最低契约版本
|
||||
|
||||
### R3.4 跨层一致性检查
|
||||
|
||||
按 `.trellis/spec/guides/cross-layer-thinking-guide.md`:
|
||||
本改动同时触碰 JS(编译器输出)、Python(Blender 消费)、契约文档三层,
|
||||
必须走该指南的检查清单。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] AC3.1 编译器输出 `manifest.json`,两个有效区域(`fengshu-er-road`、`nantaizi-lake-innovation-valley`)均含全部 12 图层声明
|
||||
- [x] AC3.2 `catalog.NATIVE_ROAD_LAYERS` 已删除,Blender 无硬编码道路图层表
|
||||
- [x] AC3.3 `.blend` 结构摘要对 Phase 0 基线一致
|
||||
(走 `.trellis/spec/guides/artifact-parity-guide.md`)
|
||||
- [x] AC3.4 **实测**:向编译器加一个 throwaway 图层 + manifest 声明,
|
||||
不改宿主任何代码,跑 blender 阶段确认它被渲染出来;验证后回滚该图层
|
||||
(父任务 AC5,见 design §3.4)
|
||||
- [x] AC3.5 `role: "semantic"` 的图层被 Blender 正确跳过(不产生几何)
|
||||
- [x] AC3.6 `center_lines` 的 white/非 white 与 `lane_separators` 的 yellow/非 yellow
|
||||
分流行为与改造前一致
|
||||
- [x] AC3.7 建筑/植被/水体渲染代码未被修改(`git diff` 验证范围)
|
||||
|
||||
## 依赖与顺序
|
||||
|
||||
- **前置**:Phase 2 完成(编译器已独立,manifest 才有"跨仓库契约"的意义)
|
||||
- 与 Phase 4 无依赖,可并行
|
||||
- 完成本阶段后,父任务 Goal 中的「道路与建筑渲染分离」才算达成
|
||||
|
||||
## 风险
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| `splitBy` 表达力不足,覆盖不了现有分流逻辑 | 先枚举 `generate_scene.py` 里全部分流分支,再定 manifest schema |
|
||||
| 材质槽名在两侧漂移 | manifest 里的 `materialLayer` 必须能被宿主校验:Blender 侧加断言,未知材质槽直接报错而非静默跳过 |
|
||||
| `.blend` 结构摘要对比粒度不够,漏掉几何差异 | 除结构摘要外,加渲染预览图人工对照 |
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 材质定义搬去编译器(材质属渲染,归宿主)
|
||||
- osm2streets legacy 图层表 `ROAD_LAYERS` 的改动
|
||||
- 建筑/植被/水体渲染逻辑
|
||||
@@ -0,0 +1,19 @@
|
||||
# P3 Debug Probe Evidence
|
||||
|
||||
Date: 2026-08-26
|
||||
|
||||
A temporary, uncommitted compiler registry entry declared `debug_probe` as a
|
||||
`marking` layer using the existing `road_surface` material slot. Its generated
|
||||
GeoJSON reused the compiled road-surface collection only for this wiring test.
|
||||
No host source was changed.
|
||||
|
||||
The compiler emitted 13 declared sources. Blender then generated
|
||||
`/private/tmp/p3-debug-probe.blend`; `SCENE_DONE` reported
|
||||
`"debug_probe": 30`. The Blender scene digest contains:
|
||||
|
||||
```json
|
||||
{"name":"Road_debug_probe","vertices":274,"polygons":30}
|
||||
```
|
||||
|
||||
The temporary registry entry was removed immediately after the proof. The
|
||||
standard v0.2.0 compiler was then rerun to restore the normal 12-source output.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Native Road 图层消费矩阵
|
||||
|
||||
调研日期:2026-08-25
|
||||
|
||||
## 证据
|
||||
|
||||
- 编译器在 `scripts/compile-native-roads.js:57,65-76` 声明并写出 12 个图层。
|
||||
- Blender 在 `blender/generate_scene.py:796-834` 遍历
|
||||
`catalog.NATIVE_ROAD_LAYERS`,只消费其中 10 个图层。
|
||||
- 当前映射及基础高度来自 `blender/osmassets/catalog.py:53-64` 与 `ROAD_LAYERS`。
|
||||
|
||||
## 当前消费与 manifest 目标
|
||||
|
||||
| 编译器 source | 当前 Blender 行为 | 当前材质槽 / z 来源 | manifest 目标 |
|
||||
|---|---|---|---|
|
||||
| `road_surface` | 直接渲染 | `road_surface` / `ROAD_LAYERS.road_surface` | `role: surface`, `materialLayer: road_surface` |
|
||||
| `edge_lines` | 直接渲染 | `lane_separators` / `ROAD_LAYERS.lane_separators` | `role: marking`, `materialLayer: lane_separators` |
|
||||
| `intersection_surface` | 直接渲染 | `intersection_surface` / `ROAD_LAYERS.intersection_surface` | `role: surface`, `materialLayer: intersection_surface` |
|
||||
| `sidewalk_surface` | 直接渲染 | `sidewalks` / `ROAD_LAYERS.sidewalks` | `role: surface`, `materialLayer: sidewalks` |
|
||||
| `lane_separators` | 按 `color` 分流 | 非 yellow: `lane_separators`; yellow: `native_lane_separator_yellow`; z 取 `lane_separators` | `role: marking`, `materialLayer: lane_separators`, `splitBy.color`(yellow 特例) |
|
||||
| `center_lines` | 按 `color` 分流 | 非 white: `center_lines`; white: `native_center_line_white`; z 取 `center_lines` | `role: marking`, `materialLayer: center_lines`, `splitBy.color`(white 特例) |
|
||||
| `direction_arrows` | 直接渲染 | `lane_arrows_webscale` / `ROAD_LAYERS.lane_arrows_webscale` | `role: marking`, `materialLayer: lane_arrows_webscale` |
|
||||
| `turn_arrows` | 直接渲染 | `lane_arrows_webscale` / `ROAD_LAYERS.lane_arrows_webscale` | `role: marking`, `materialLayer: lane_arrows_webscale` |
|
||||
| `crosswalks` | 直接渲染 | `crosswalks` / `ROAD_LAYERS.crosswalks` | `role: marking`, `materialLayer: crosswalks` |
|
||||
| `vehicle_stop_lines` | 直接渲染 | `vehicle_stop_lines` / `ROAD_LAYERS.vehicle_stop_lines` | `role: marking`, `materialLayer: vehicle_stop_lines` |
|
||||
| `lane_centerlines` | 不进入 Blender 遍历 | 无 | `role: semantic`,Blender 跳过 |
|
||||
| `connectors` | 不进入 Blender 遍历 | 无 | `role: semantic`,Blender 跳过 |
|
||||
|
||||
## 结论与实施约束
|
||||
|
||||
- manifest 必须声明全部 12 个编译器图层,不能再用“未出现在列表中”表达不渲染。
|
||||
- `role: semantic` 的两个图层不得读取 GeoJSON 或创建 Blender 几何。
|
||||
- `splitBy` 至少需表达属性 `color` 的精确匹配与默认分支,且分流后沿用同一个基础材质槽的 z 值。
|
||||
- Blender 消费 manifest 时,未知 `materialLayer`、缺失 source 文件、或 source 未在 manifest 声明都必须报错;不能静默跳过。
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "rc-p3-render-separation",
|
||||
"name": "rc-p3-render-separation",
|
||||
"title": "Phase 3:道路与建筑渲染分离",
|
||||
"description": "编译器输出 layer manifest 自声明图层,Blender 改为读 manifest;道路渲染从 generate_scene.py 抽离,消除跨仓库重复图层表",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-25",
|
||||
"completedAt": "2026-08-26",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": "08-25-road-compiler-extraction",
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user