7.5 KiB
图层表:跨语言的单一事实源
适用:改动 osm2streets 九个渲染图层的任何一方——新增图层、删图层、调顺序、调 颜色、调高度。动手前必读,这里的错误不会报错,只会让产物静默错栈。
一句话
九个图层在 JS 和 Python 各存一份表,两份故意只同步"集合与顺序"、不同步颜色,
一致性靠运行时的 catalog.check_layers() 用产物文件对账。
两份表分别管什么
| JS 侧 | Python 侧 | |
|---|---|---|
| 位置 | scripts/lib/scene-layers.js:15 SCENE_LAYERS |
blender/osmassets/catalog.py:28 ROAD_LAYERS |
| 服务于 | 2D 调试链路:GeoJSON 拆分、GeoPackage 导入、QGIS 工程符号 | 3D 场景链路:Blender 材质与几何高度 |
| 关键字段 | id、splitKey、zIndex、title、fill/outline(sRGB hex) |
id、material、color(线性 RGB)、z(米) |
| 消费点 | build-osm2streets-qgis.js:91,98,109,1315、reimport-gpkg.js:53,63,77 |
generate_scene.py:759,844 |
id 是两侧唯一的连接键,同时也是 GeoJSON 文件名的 stem(layerFile() 拼
<id>.geojson,见 scene-layers.js:103)。
这份表从前复制了四遍
scene-layers.js:3-13 的注释写明了它存在的理由:同一批图层的顺序曾同时躺在
merged-scene 的 z_index 表、场景样式 JSON、生成的 QGIS 工程、以及 README 的手工重建
片段里。加一个图层要同步改四处,漏一处不报错,只是下游 Blender/Cesium 里的场景
悄悄错栈。
catalog.py:3-7 记录的是 Python 侧的同一个病:九个图层的绘制顺序在 JS、Blender 高度
在一个 layer_z dict、颜色在一个 road_mats dict——两种语言三份拷贝,手工对齐。
推论:看到任何地方开始第二次枚举这九个图层,那就是 bug 的温床,改成从这两份表 之一派生。
为什么颜色刻意不同步
catalog.py:11-15 明确列为"deliberate non-goal":
scene-layers.js的fill是给 QGIS 2D 调试地图用的 sRGB hexcatalog.py的color是给 Blender 3D 场景用的线性 RGB- 两套值是分别调出来的,不存在换算关系
所以 check_layers() 只校验图层的集合与顺序——那是必须一致的部分——不碰调色板。
不要"顺手统一"两边的颜色。那不是清理重复,是把两个独立的设计意图合并成一个错的。
对账机制
桥梁是产物文件 osm2streets_scene_style.json(两侧常量都叫 SCENE_STYLE_FILE,
见 scene-layers.js:101 与 catalog.py:49):
JS 侧 sceneStyle() ──写──▶ osm2streets_scene_style.json ──读──▶ catalog.check_layers()
scene-layers.js:126 (落在 geojson 输出目录) catalog.py:162
写入点:build-osm2streets-qgis.js:100(intermediates 阶段)、
reimport-gpkg.js:79(reimport 阶段)。
读取点:generate_scene.py:842,每次构建场景时执行。
check_layers() 报三类问题(catalog.py:183-194):
- style 里有、
ROAD_LAYERS里没有 → 该图层到不了 3D 场景 ROAD_LAYERS里有、style 里没有 → 不会有 GeoJSON 产出给它- 集合相同但顺序不同 → 打印两侧的实际顺序
这是 warn 不是 fail(catalog.py:168-169 写明理由):过期或缺失的输出目录不该
阻断一次重建。所以——
构建日志里的
Layer catalog warning:不是噪音。它是这套双表设计唯一的自动 报警,被忽略就等于没有。
顺序是承重的
catalog.py:16-18:
- 材质创建顺序固定了导出 GLB 里的材质索引
- 图层顺序固定了 mesh 创建顺序
所以 ROAD_LAYERS 和 MATERIALS 是 list 不是 dict,追加是唯一安全的编辑。
在中间插入一个图层会平移其后所有材质索引——GLB 结构变了,parity 校验会红,
Cesium 侧引用的材质会错位。
JS 侧的 zIndex 同样兼作绘制顺序(scene-layers.js:12),最小值先画、位于栈底。
它同时是写进每个 feature 的 z_index 属性(mergeScene(),scene-layers.js:117-119)。
派生函数:只加派生,不要加第二份枚举
scene-layers.js 导出的四个派生函数是这份表的全部合法用法:
| 函数 | 位置 | 用途 |
|---|---|---|
layerFile(layer) |
:103 |
<id>.geojson 文件名 |
mergeScene(getCollection) |
:109 |
合成 osm2streets_scene.geojson,逐 feature 打上 render_layer / z_index |
sceneStyle() |
:126 |
生成对账用的 style JSON |
qgisRgba(hex, alpha) |
:143 |
hex → QGIS 要的 "r,g,b,a" 字符串 |
mergeScene 收的是回调而不是数组,这样 build 阶段(从内存的 split 取)和
reimport 阶段(从磁盘读回)能共用同一套合并逻辑(scene-layers.js:107-108)。
新增第三种数据来源时沿用这个模式,不要复制合并循环。
outline: null 表示无描边,QGIS 侧由 qgisRgba 转成全透明(scene-layers.js:13-14,145)。
Python 侧同理:road_material_specs()(catalog.py:156)把 ROAD_LAYERS 转成
MATERIALS 形状的规格,generate_scene.py:759 用 zip 与图层配对——保持这条派生链,
不要在 generate_scene.py 里另起一份材质名列表。
改动清单
新增一个图层
scene-layers.js:SCENE_LAYERS末尾追加:id、splitKey、zIndex(大于现有 最大值)、title、fill、outline、outlineWidth- 确认 osm2streets 的拆分结果里确实有
splitKey对应的键 (build-osm2streets-qgis.js:92取split[layer.splitKey]) catalog.py:ROAD_LAYERS末尾追加:id(与第 1 步一致)、material(新名字)、color(线性 RGB,独立调)、z(米,高于前一层避免 z-fighting)- 跑一次
intermediates+blender,确认日志里没有Layer catalog warning: - 该图层的 GeoPackage 导入、QGIS 符号、场景合并、reimport 全部自动跟上,无需再
改
reimport-gpkg.js或 QGIS 工程生成代码
删除一个图层
两侧同时删。只删一侧的话 check_layers() 会 warn,但构建照常出产物——一份少了
该图层的产物。
调整顺序
改 zIndex 的同时必须把 ROAD_LAYERS 的元素位置也调成一致。注意这会移动材质
索引,属于会改变产物的变更,必须跑 parity 校验,见
产物一致性指南。
只调颜色
改一侧即可,不要同步到另一侧(见上文"为什么颜色刻意不同步")。
反模式
| 反模式 | 后果 |
|---|---|
在 generate_scene.py / QGIS 生成代码里硬编码图层名列表 |
回到"复制四份"的旧病 |
从 scene-layers.js 的 fill 换算 Blender 的 color |
抹掉两套独立调过的配色 |
在 ROAD_LAYERS / MATERIALS 中间插入条目 |
GLB 材质索引整体平移 |
把 ROAD_LAYERS / MATERIALS 改成 dict |
顺序语义丢失,见 catalog.py:16-18 |
把 check_layers() 从 warn 改成 raise |
输出目录过期就无法重建 |
忽略 Layer catalog warning: |
双表设计唯一的报警失效 |
相关
- 外部工具调用:图层如何进出 GeoPackage
- CLI 与阶段:哪个阶段写、哪个阶段读这些文件
- Blender 资产生成:
MATERIALS的其余部分 - 产物一致性指南:改动顺序后如何验证