docs: Archive osmassets refactor plan

This commit is contained in:
2026-08-03 12:12:49 +08:00
parent 0b8195b43f
commit 68829214fb
8 changed files with 90 additions and 118 deletions

View File

@@ -85,7 +85,7 @@ def assemble(ring, [way_id,] scene_xmin, scene_xmax, scene_ymin, scene_ymax,
### 加一种新 OSM 要素 ### 加一种新 OSM 要素
目标形态`docs/refactor-plan.md`**新增一个模块 + 注册一行,不改 `build()`**。 目标形态:**新增一个模块 + 注册一行,不改 `build()`**。
1. 新建 `osmassets/<feature>.py`,写 `assemble(...)`,签名照抄上面 1. 新建 `osmassets/<feature>.py`,写 `assemble(...)`,签名照抄上面
2. 只 import 需要的:`from osmassets.geom import clip_polygon` 2. 只 import 需要的:`from osmassets.geom import clip_polygon`
@@ -176,7 +176,7 @@ export_cesium.py # 优先读 material custom property
否则新生成的 `.blend` 不会自带契约 否则新生成的 `.blend` 不会自带契约
- `catalog.py` 仍属纯 Python 层,不能 import `bpy`;序列化发生在 `materials.py` - `catalog.py` 仍属纯 Python 层,不能 import `bpy`;序列化发生在 `materials.py`
- `"Office White Metal Facade"` 在四张表里都有,但 `catalog` 里**已无此材质** - `"Office White Metal Facade"` 在四张表里都有,但 `catalog` 里**已无此材质**
`docs/refactor-plan.md` 记为缺陷 D1。它只能作为旧 `.blend` 回退兼容存在, 历史上记为缺陷 D1。它只能作为旧 `.blend` 回退兼容存在,
不要迁回新契约源 不要迁回新契约源
**改材质名时**`catalog.MATERIALS` + `catalog.ROAD_LAYERS` + 四张旧回退表全部 **改材质名时**`catalog.MATERIALS` + `catalog.ROAD_LAYERS` + 四张旧回退表全部

View File

@@ -57,7 +57,7 @@ node scripts/parity.js compare control-1 control-2 # 必须全绿
没做这步就开始改代码,你会分不清一个差异是"重构引入的 bug"还是"本来就每次都不一样"。 没做这步就开始改代码,你会分不清一个差异是"重构引入的 bug"还是"本来就每次都不一样"。
已完成的 control 结论`docs/refactor-plan.md` 已完成的 control 结论:
- `.blend` **结构摘要两次完全一致** ← 这是主校验信号,可信 - `.blend` **结构摘要两次完全一致** ← 这是主校验信号,可信
- `.blend` 文件 sha256 不一致 - `.blend` 文件 sha256 不一致
@@ -147,7 +147,7 @@ capturedAt / durationMs / label
## 风险高的改动要分次提交 ## 风险高的改动要分次提交
`docs/refactor-plan.md` 对风险最高的一期写着 要素注册表这类高风险重构必须按要素分次提交
> 逐要素分次提交,每次单独跑 parity。 > 逐要素分次提交,每次单独跑 parity。
@@ -155,9 +155,9 @@ capturedAt / durationMs / label
--- ---
## 当前重构进度`docs/refactor-plan.md` ## 当前重构进度
那份计划是**临时工作文档**P3 收尾后会并入 changelog 并删除。当前状态 临时施工计划已删除;长期状态以本指南和 `docs/changelog.md` 为准
| 期 | 内容 | 状态 | | 期 | 内容 | 状态 |
|---|---|---| |---|---|---|

View File

@@ -0,0 +1,2 @@
{"file": ".trellis/spec/guides/artifact-parity-guide.md", "reason": "Check that parity/control knowledge survives after deleting the temporary refactor plan."}
{"file": ".trellis/spec/guides/index.md", "reason": "Check guide references remain accurate and no stale refactor-plan links remain."}

View File

@@ -0,0 +1,2 @@
{"file": ".trellis/spec/guides/artifact-parity-guide.md", "reason": "Contains refactor-plan status and references that must be preserved without linking to the deleted temporary file."}
{"file": ".trellis/spec/guides/index.md", "reason": "Shared guide routing for cross-layer and parity documentation changes."}

View File

@@ -0,0 +1,35 @@
# Archive refactor plan
**类型**docs · **范围**docs/spec · **创建**2026-08-03
---
## Goal
收尾临时文档 `docs/refactor-plan.md`:把仍有价值的 P0-P3 重构结论并入长期文档,
然后删除这份已过期的临时计划,避免后续 AI 或开发者读到 P3 未做、旧行号、旧 `CESIUM_EXPORT`
状态等过期事实。
## Requirements
1. `docs/changelog.md` 必须新增一条 2026-08-03 记录总结材质导出契约化、Trellis
spec 初始化,以及 `docs/refactor-plan.md` 的收尾处理。
2. 删除 `docs/refactor-plan.md`,因为它开头已声明 P3 收尾后应并入 changelog 并删除。
3. 更新 `.trellis/spec/guides/artifact-parity-guide.md` 中对 `docs/refactor-plan.md`
直接依赖,保留 parity/control 结论和 P0-P3 当前状态,但不引用已删除文件。
4. 不改业务代码,不改 Blender/Cesium 产物,不修 D1-D3。
5. 删除后不得留下指向 `docs/refactor-plan.md` 的断链引用。
## Acceptance Criteria
- [ ] `docs/refactor-plan.md` 不存在。
- [ ] `docs/changelog.md` 顶部有 2026-08-03 条目,记录 P3 完成和临时计划归档。
- [ ] `rg "docs/refactor-plan.md|refactor-plan" docs .trellis/spec README.md` 不再发现活文档引用。
- [ ] `git diff --check` 通过。
- [ ] 工作范围只包含 docs、`.trellis/spec` 和当前 Trellis task 文件。
## Out of Scope
- P2 要素注册表补完。
- D1/D2/D3 修复。
- 任何 `blender/``scripts/``config/` 业务代码改动。

View File

@@ -0,0 +1,30 @@
{
"id": "archive-refactor-plan",
"name": "archive-refactor-plan",
"title": "Archive refactor plan",
"description": "Move completed osmassets refactor-plan conclusions into changelog and remove the stale temporary plan.",
"status": "in_progress",
"dev_type": "docs",
"scope": "docs/spec",
"package": null,
"priority": "P2",
"creator": "dingkang",
"assignee": "dingkang",
"createdAt": "2026-08-03",
"completedAt": null,
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [
"docs/changelog.md",
"docs/refactor-plan.md",
".trellis/spec/guides/artifact-parity-guide.md"
],
"notes": "Lightweight docs cleanup. Remove stale temporary refactor plan after merging durable conclusions into changelog/spec.",
"meta": {}
}

View File

@@ -1,5 +1,20 @@
# Changelog # Changelog
## 2026-08-03
- 初始化 Trellis 项目规范,把 `trellis init` 误生成的 frontend spec 替换为本项目真实的
`pipeline` / `blender` / `preview` / `config` 四层规范,并把跨层 parity、图层顺序、
外部工具 staging、纯 Python / bpy 边界等反直觉约定固化到 `.trellis/spec/`
- 完成 Cesium 材质导出契约化:`catalog.MATERIALS[*]["cesium"]` 现在由
`materials.from_spec()` 写入 `.blend` 材质自定义属性 `material["cesium_export"]`
`export_cesium.py` 优先读取该属性;旧四张材质名表仅保留为旧 `.blend` 回退路径。
parity before/after 只有 `.blend` 新增 `props.cesium_export``.blend` bytes 变化,
无 GLB/material/metadata 结构漂移。
- 收尾临时 `osmassets` 重构施工计划P0/P1/P3 的长期知识已经进入 changelog 和 Trellis spec
P2 仍是后续重构方向(`building` / `fountain` / `roads` 仍在 `generate_scene.py` 里,
尚未形成完整 `features/` 注册表)。删除临时计划文件,避免继续传播旧行号和
`catalog.CESIUM_EXPORT` 死代码等过期事实。
## 2026-07-31远看发黑的真正原因反照率没被提亮 ## 2026-07-31远看发黑的真正原因反照率没被提亮
(二)里加的 emissive 提到 0.8 仍然发黑。原因是 emissive 乘的是本来就很暗的 (二)里加的 emissive 提到 0.8 仍然发黑。原因是 emissive 乘的是本来就很暗的

View File

@@ -1,112 +0,0 @@
# 重构施工计划:`osmassets` 包化P0P3
> 临时工作文档。P3 收尾后把结论并入 `docs/changelog.md`,本文件删除。
## 目标
把「从 OSM 生成 Blender / Cesium 资产」的逻辑从两个单体脚本里拆成可复用的库,使得:
- 新增一种 OSM 要素 = 新增一个 `features/*.py` + 注册一行,不改 `build()`
- 道路图层表、材质规格只有一份定义JS 侧与 Python 侧不再各存一份
- `export_cesium.py` 不再靠材质名字符串跟 `generate_scene.py` 对接
- 纯几何 / 解析逻辑脱离 `bpy`,可用系统 python 直接测
## 硬约束:严格产物一致
P0P3 全程 **不改变任何输出**。每期结束必须通过 parity 校验,任何差异都要么消除、要么在本文件里逐条记录原因。
已知缺陷(本轮**只记录、不修**
| # | 位置 | 现象 |
|---|---|---|
| D1 | `export_cesium.py:26,34,40,52` | `"Office White Metal Facade"` 四张表里都有,`generate_scene.py` 里已无此材质——死条目 |
| D2 | `scene-layers.js:15` vs `generate_scene.py:1017` | 同一批图层的颜色两侧各自手调,无一致性保证 |
| D3 | `generate_scene.py:788` | `tuft_density_wave` 注释仍在跟已删除的 hedge banding 作对比 |
## Parity 工具与基线
`outputs/` 已在 `.gitignore` 中,基线快照放 `outputs/_refactor-baseline/`,不入库。
| 工具 | 位置 | 作用 |
|---|---|---|
| 场景摘要 | `blender/tools/scene_digest.py` | 在 Blender 内打开 `.blend`,输出稳定 JSON对象名/顶点数/面数/材质槽/自定义属性、材质参数、场景属性 |
| GLB 摘要 | `scripts/glb-digest.js` | 纯 Node 读 GLB 的 JSON chunk输出 node/mesh/material 清单与 PBR 参数,附 buffer 字节长度 |
| 驱动 | `scripts/parity.sh <label>` | 跑 blender+cesium 阶段 → 收集 `SCENE_DONE` / `CESIUM_EXPORT_DONE` / 两份摘要 / 渲染 PNG 到 `outputs/_refactor-baseline/<label>/` |
**先做对照实验control**用未改动的代码连跑两次diff 两份摘要。这一步确定哪些字段天然不确定,把这些字段列入忽略名单。没做这步的 parity 校验是假的。
已完成,结论如下(`control-1` vs `control-2`,两区域):
- `.blend` **结构摘要两次完全一致** —— 这是主校验信号,可信
- `.blend` 文件 sha256 不一致:内嵌绝对路径 + 图片打包顺序随哈希表走
- 渲染 PNG sha256 不一致EEVEE 非位级可复现
- GLB 结构node / mesh / primitive / material / image两次完全一致但 accessor 数 399 vs 398、buffer 差 720 字节glTF 导出器会去重相同 accessor`smart_project` 的 UV 带浮点噪声,一次能去重一次不能
忽略名单(写在 `scripts/parity.js:IGNORED_PATHS`,附原因):`files.{blend,glb,render}.sha256``files.{glb,render}.bytes``glbDigest.{fileBytes,buffers,counts.accessors}`
保留比对的即真正的契约:`SCENE_DONE` / `CESIUM_EXPORT_DONE` 标记、`.blend` 全量结构摘要、GLB 的 node/mesh/material/image 结构、`<area>.json` 元数据。加上 `control-1``control-2` 两份基线已落盘。
样本区域:
- `nantaizi-lake-innovation-valley` — 主样本OSM + osm2streets GeoJSON 齐全
- `hanyang-block` — 次样本,只有 `intermediates` 产物,需先补跑一次 blender 阶段生成基线
## 分期
### P0 — 抽纯函数(行为零变化)
新建 `blender/osmassets/`,只搬运、不改逻辑:
| 目标文件 | 从 `generate_scene.py` 搬入 | 依赖 |
|---|---|---|
| `osm.py` | `tags` (94)、`parse_osm` (99)、`Projector` (140)、`parse_height` (506) | 无 bpy |
| `geom.py` | `geometry_rings` (406)、`feature_in_bounds` (418)、`clip_polygon` (426)、`sample_tree_row` (513)、`polygon_area` (688)、`point_in_polygon` (697)、`distance_to_ring` (712) | 无 bpy |
- `generate_scene.py` 顶部加 `sys.path` 引导(`--factory-startup``blender/` 不在 `sys.path`),改为 `from osmassets import ...`
- 新增 `blender/tests/test_geom.py``test_osm.py``unittest` 标准库,系统 `python3` 直接跑(本机 3.9,避免 3.10+ 语法)
- 验收:`python3 -m unittest discover blender/tests` 通过 + parity 全绿
### P1 — 单一定义源
新建 `blender/osmassets/catalog.py`
- `ROAD_LAYERS``id` / `blender_z` / `material_name` / `color`,替换 `generate_scene.py:1017``road_mats``1122``layer_z` 两份副本
- `MATERIAL_SPECS`:目前散在 `build()` 里的全部 `make_material` / `make_textured_material` 调用参数
- 新增一致性检查:读输出目录里已存在的 `osm2streets_scene_style.json`,比对图层 id 集合与顺序,不一致则打 warning**不**改颜色,改了就破坏 parity → 见 D2
验收parity 全绿;手动删一个图层 id 验证 warning 生效。
### P2 — 要素注册表
新建 `blender/osmassets/features/`,每种要素一个模块,导出 `SPEC`
```
water.py natural=water / water=lake
grass.py landuse=grass含 tuft 散布)
scrub.py natural=scrub
tree.py natural=tree 节点 + natural=tree_row + 两种树风格
building.py building=*(含 roof / windows
fountain.py amenity=fountain
roads.py osm2streets GeoJSON 图层 + highway 折线回退
```
- `scene.py::assemble()` 遍历注册表;`build()` 收缩为「解析 → assemble → 灯光相机 → 存盘渲染」
- 计数器改由注册表汇总,但 `SCENE_DONE``scene[...]` 的键名、顺序保持逐字不变
- if/elif 的**匹配顺序**是语义的一部分(`building` 分支在最后),注册表必须保序
验收parity 全绿 —— 这期风险最高,逐要素分次提交,每次单独跑 parity。
### P3 — 材质契约化
- `catalog.py` 的材质规格扩展出 cesium 段:`tint` / `metallic` / `base_color` / `emission`
- `generate_scene.py` 把规格写进材质自定义属性 `material["cesium_export"] = json.dumps(spec)`
- `export_cesium.py` 优先读自定义属性;读不到时回落到现有四张名字表(**原样保留,含 D1 死条目**),保证旧 `.blend` 仍能导出且 parity 成立
- `Tree Crown` 的程序化贴图特例保持不变
验收parity 全绿;另外用重构前生成的旧 `.blend` 跑一次导出,确认回落路径可用。
## 不在本轮范围
- 输出目标可插拔(整场景 / 每要素单独 GLB——原 P4
- `build-area.js` 里 390 行内联 HTML 与手写 glTF 的拆分——原 P4
- 上表 D1D3 的修复