Files
osmWorkflow/README.md
2026-08-04 09:16:14 +08:00

263 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OSM Asset Pipeline
把单个园区/片区 OSM XML 转为可消费的 Blender 场景和 Cesium GLB。osm2streets GeoJSON、GeoPackage、QGIS 工程和预览图都是中间资产,用来提供道路几何、调试标线效果,以及给 Blender/Cesium 生成提供输入。
## 目标产物
每个区域默认输出到 `outputs/<area-id>/`
- `<area-id>.blend`Blender 场景,包含道路、建筑、水体、植被等
- `<area-id>.png`Blender 预览渲染
- `<area-id>.glb`Cesium 可加载的 3D 模型
- `<area-id>.json`Cesium 放置元数据和示例代码
- `<area-id>-cesium-preview.html`Cesium 本地预览页
- `<area-id>-compressed-webp768.glb/json/html`:显式 `compress` 阶段生成的可选压缩预览产物
- `osm2streets_web_out/`osm2streets GeoJSON 中间层
- `<area-id>.gpkg` / `<area-id>.qgz` / `<area-id>-preview.png`QGIS 调试资产
## 环境
需要:
- macOS QGIS默认 `/Applications/QGIS.app`
- Blender默认 `/Applications/Blender.app`
- Node.js / npm
首次使用:
```bash
cd /Users/que01/osm2streets-qgis-workflow
npm install
```
## 主流程
默认构建南台子湖创新谷样例:
```bash
npm run build
```
指定区域配置:
```bash
npm run build:area -- --config config/areas/hanyang-block.json
```
只跑部分阶段:
```bash
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages intermediates
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages blender
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages cesium
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages preview
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages compress
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages reimport
```
`intermediates` 会生成 osm2streets GeoJSON、GeoPackage、QGIS 工程和 QGIS 预览图。`blender` 使用 OSM 和 osm2streets GeoJSON 生成 `.blend`/`.png``cesium``.blend` 导出 `.glb`/`.json`,并生成 Cesium 预览 HTML。`preview` 只在已有 `.glb/.json` 时补生成 HTML。`compress` 从已有 `.glb/.json/html` 生成并列压缩产物,不覆盖默认 GLB。`reimport` 把手工编辑过的 GeoPackage 回导为 GeoJSON不含在 `all` 里,详见 [QGIS 手工修正工作流](#qgis-手工修正工作流)。
`compress` 不含在 `all` 里,也不能从配置文件默认开启。需要重导出 Cesium 后立刻生成压缩产物时,显式跑:
```bash
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages cesium,compress
```
## 区域诊断
手工编辑 OSM 或怀疑产物变大时先跑快速诊断。它只读取区域配置、OSM XML 和已有输出
文件,不会启动 QGIS、Blender 或 Cesium 构建:
```bash
npm run diagnose:area -- --config config/areas/nantaizi-lake-innovation-valley.json
```
诊断会输出 OSM bounds、building way / multipolygon relation、显式高度、植被数量、
现有产物状态,以及 GLB 的 size / nodes / meshes / materials / images / extensions。
缺少已期望的基线产物、异常 building relation、GLB 超过保守预算等会进入 `Warnings`
## 区域配置
新区域从模板复制:
```bash
cp config/examples/template.json config/areas/my-area.json
```
核心配置:
```json
{
"id": "my-area",
"input": "/absolute/path/to/input.osm",
"outputRoot": "/absolute/path/to/outputs",
"qgisApp": "/Applications/QGIS.app",
"blenderApp": "/Applications/Blender.app",
"stages": {
"intermediates": true,
"blender": true,
"cesium": true
},
"qgis": {
"arrowScale": 0.8,
"arrowMergeTriangles": true,
"arrowOutlineSimplifyMeters": 0.05,
"intersectionCornerSourceMaxDimensionMeters": 2.6,
"clipPad": 0.002,
"canvasPad": 0.001,
"previewPad": 0.0007,
"canvasExtent": null,
"previewExtent": null,
"layerPrefix": "osm2streets"
},
"blender": {
"treeStyle": "natural",
"officeOverrides": ""
},
"compress": {
"textureSize": 768,
"quality": 82,
"effort": 80,
"meshopt": false
}
}
```
QGIS road-layer knobs:
- `arrowScale`: scales osm2streets lane-arrow polygons before export.
- `arrowMergeTriangles`: merges each osm2streets lane-arrow triangle mesh into one valid polygon. This preserves the original arrow shape and turn direction while removing renderer gaps along shared triangle edges.
- `arrowOutlineSimplifyMeters`: removes sub-decimeter kinks from the merged arrow exterior. The default `0.05` removes the two malformed tail vertices without changing the arrow head; the remaining tail edge is aligned perpendicular to the shaft.
- `intersectionCornerSourceMaxDimensionMeters`: keeps only small osm2streets `sidewalk corner` polygons. Large intersection-marking polygons are not treated as sidewalk because they can cover the drivable junction.
`scripts/build-area.js` 会按 `id` 自动推导默认输出路径。确实需要定制时,可以增加 `outputs` 覆盖:
```json
{
"outputs": {
"areaDir": "/absolute/path/to/custom-area",
"blend": "/absolute/path/to/custom.blend",
"glb": "/absolute/path/to/custom.glb",
"cesiumPreview": "/absolute/path/to/custom-preview.html",
"compressedGlb": "/absolute/path/to/custom-compressed.glb"
}
}
```
预览 Cesium 页面时,需要在输出目录启动 HTTP 服务,避免浏览器拦截本地文件请求:
```bash
cd outputs/my-area
python3 -m http.server 8765
```
然后打开 `http://localhost:8765/my-area-cesium-preview.html`
## 实验:车辆巡航
`preview``cesium` 阶段会额外生成 `<area-id>-vehicle-route.json``<area-id>-vehicle-car.gltf`。路线文件从 OSM bounds 内的可行驶 `highway` way 提取道路中心线,并向右偏移约 1.3 米作为车辆行驶线避免车辆压道路中心线。Cesium 预览页会加载多条道路段并显示多辆实验车辆循环巡航;`Vehicle` 下拉框决定 `Follow` 跟随哪一辆车。
这是用于验证高精度巡航可用性的预览层功能,不会改变 Blender/GLB 主资产本身。车辆模型是无 logo 的轻量预览模型,生成在输出目录中。
## 已沉淀区域
- `config/areas/nantaizi-lake-innovation-valley.json`
- `config/areas/hanyang-block.json`
## 低层命令
通常优先使用 `npm run build:area`。如果只想调试旧 QGIS/osm2streets 阶段,可以直接运行:
```bash
npm run build:qgis -- --config config/hanyang-block.json
```
Blender 低层命令:
```bash
/Applications/Blender.app/Contents/MacOS/Blender \
--background --factory-startup \
--python blender/generate_scene.py -- \
--osm "/path/to/input.osm" \
--geojson "/path/to/osm2streets_web_out" \
--output "/path/to/scene.blend" \
--render "/path/to/preview.png" \
--tree-style natural
```
`--tree-style` 可选 `natural``procedural``shapespark``shapespark` 使用
`assets/models/custom/shapespark_plants/` 里的拆分低模植物资产;模型缺失时会回落到
`natural`
Cesium GLB 低层导出:
```bash
/Applications/Blender.app/Contents/MacOS/Blender \
--background \
--python blender/export_cesium.py -- \
--blend "/path/to/scene.blend" \
--glb "/path/to/scene.glb" \
--metadata "/path/to/scene.json"
```
详见 [blender/README.md](blender/README.md)。
## 压缩 GLB
推荐使用显式 `compress` 阶段。它不会覆盖默认 `<area-id>.glb`,只生成并列的压缩 GLB、
metadata 和预览页:
```bash
npm run build:area -- \
--config config/areas/nantaizi-lake-innovation-valley.json \
--stages compress
```
底层脚本也可以单独调用:
```bash
npm run compress:glb -- \
--input outputs/nantaizi-lake-innovation-valley/nantaizi-lake-innovation-valley.glb \
--output outputs/nantaizi-lake-innovation-valley/nantaizi-lake-innovation-valley-compressed-webp768.glb \
--texture-size 768 \
--metadata outputs/nantaizi-lake-innovation-valley/nantaizi-lake-innovation-valley.json \
--preview outputs/nantaizi-lake-innovation-valley/nantaizi-lake-innovation-valley-cesium-preview.html
```
该脚本通过 `npx @gltf-transform/cli@4.1.4` 执行 `resize -> webp`。如需进一步压几何,
可追加 `--meshopt`,但会引入 `EXT_meshopt_compression` / `KHR_mesh_quantization`
应先确认目标 Cesium 版本加载正常。
## QGIS 手工修正工作流
如果已经在现成的 `.qgz` 项目里直接编辑了 `gpkg` 图层,不要再重跑 `intermediates`,否则会把手工修改覆盖掉。推荐流程是:
1. 在 QGIS 中打开 `outputs/<area-id>/<area-id>.qgz`
2. 直接编辑项目内关联的 `gpkg` 图层并保存
3.`reimport` 回导 GeoJSON 并重建场景,再接 `blender,cesium`
南台子湖创新谷当前可直接使用下面这条命令:
```bash
npm run build -- --config config/areas/nantaizi-lake-innovation-valley.json --stages reimport,blender,cesium
```
`reimport` 阶段(`scripts/reimport-gpkg.js`)做两件事:
-`<area-id>.gpkg` 里的 9 个图层逐个导出到 `osm2streets_web_out/<layer>.geojson`
-`scripts/lib/scene-layers.js` 的图层表重建 `osm2streets_scene.geojson`(写入 `render_layer` / `z_index`)和 `osm2streets_scene_style.json`
说明:
- 这套流程假设你的手工修改已经保存在 `outputs/<area-id>/<area-id>.gpkg`
- 所有图层先导出到临时目录并校验通过后才写回 `osm2streets_web_out/`;任一图层缺失或导出结果不是合法 FeatureCollection整批都不落盘`ogr2ogr` 遇到不存在的图层会留下 0 字节文件,直接覆盖会静默损坏数据)
- `intermediates``reimport` 互斥,同时指定会直接报错:前者用 OSM 重建 `gpkg`,正好会抹掉后者要读回的手工修改
- `blender,cesium` 阶段读取的是 `osm2streets_web_out/*.geojson`,不是直接读取 `gpkg`
- 如果 Blender 当前环境不稳定,先确认 `geojson` 已完成回导,再单独排查 Blender 本身
- 增删图层或调整 `z_index` 只需改 `scripts/lib/scene-layers.js`构建、场景合并、场景样式、QGIS 工程会一并同步
## 文档
- [docs/input-cases.md](docs/input-cases.md) - 已验证的 OSM 输入案例
- [docs/changelog.md](docs/changelog.md) - 变更记录