que01 eb4a0d9b2a fix: 树发黑的真正原因是反照率没提亮,并加饱和度让远看更绿
emissive 提到 0.8 仍然发黑:它乘的是本来就很暗的反照率,0.8 × 深绿约等于
sRGB [0.22, 0.31, 0.11],还是暗的。要提的是反照率本身。

Cesium 截图定位:草亮黄绿、建筑近白、路面浅灰,只有树暗。这棵树图集的叶片
本来就是深绿(绿色系像素均值 sRGB [0.249, 0.35, 0.12]),按真实反照率渲染
是对的,但场景里其他材质都被手工提亮过——EXPORT_TINTS 草 0.72、带肋墙面
0.86,EXPORT_EMISSION_OVERRIDES 建筑 0.18,全是针对 Cesium 偏白的默认光照
调出来的。新资产没调过,是唯一如实渲染的东西,放旁边就显得发黑。

- FOLIAGE_ALBEDO_GAIN = 2.1,在抠图植被 dilate 那一遍顺带乘上。用增益而非
  tint:其他材质是单一表面,而这是同时装着叶片/树皮/果实的图集,往绿色混会
  把树干染绿。缩放保留色相关系,只把整体抬到和邻居一样的曝光。
- FOLIAGE_SATURATION = 1.75,绕各像素自身 Rec.709 亮度做饱和度拉伸。图集本
  来就偏灰(平均饱和度 0.22),远看时 mip 把叶片、树皮、缝隙混在一起会更往
  中性靠。绕亮度拉伸把叶片推绿而基本不动本来中性的部分,也没有绿色 tint 强
  加给树干的色相偏移。叶片 sRGB → [0.262, 0.529, 0.021],饱和度 0.22 → 0.34,
  过曝到纯白的像素占 0.3%。
- FOLIAGE_EMISSION 回调 0.25,它只负责给背光面兜底。
- 新增 triangulate_mesh():export_tangents 打开后刷了 55 行「切向空间只能只算
  三角/四边形」,MeshBatch 建的 OSM 轮廓都是 n-gon。glTF 只有三角形,导出时
  无论如何都会三角化,提前做不改变任何输出三角形(三角数 51719 前后一致),
  切线 49/102 → 102/102,警告归零。

被数据排除的假设:贴图颜色全链路逐位一致;模拟 mip 链可见像素亮度
0.127→0.124;法线贴图抠图区是干净平面法线;GLB 重新导入 Blender 渲染正常。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 13:23:44 +08:00

OSM Asset Pipeline

把单个园区/片区 OSM XML 转为可消费的 Blender 场景和 Cesium GLB。osm2streets GeoJSON、GeoPackage、QGIS 工程和预览图都是中间资产,用来提供道路几何、调试标线效果,以及给 Blender/Cesium 生成提供输入。

目标产物

每个区域默认输出到 outputs/<area-id>/

  • <area-id>.blendBlender 场景,包含道路、建筑、水体、植被等
  • <area-id>.pngBlender 预览渲染
  • <area-id>.glbCesium 可加载的 3D 模型
  • <area-id>.jsonCesium 放置元数据和示例代码
  • <area-id>-cesium-preview.htmlCesium 本地预览页
  • osm2streets_web_out/osm2streets GeoJSON 中间层
  • <area-id>.gpkg / <area-id>.qgz / <area-id>-preview.pngQGIS 调试资产

环境

需要:

  • macOS QGIS默认 /Applications/QGIS.app
  • Blender默认 /Applications/Blender.app
  • Node.js / npm

首次使用:

cd /Users/que01/osm2streets-qgis-workflow
npm install

主流程

默认构建南台子湖创新谷样例:

npm run build

指定区域配置:

npm run build:area -- --config config/areas/hanyang-block.json

只跑部分阶段:

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 reimport

intermediates 会生成 osm2streets GeoJSON、GeoPackage、QGIS 工程和 QGIS 预览图。blender 使用 OSM 和 osm2streets GeoJSON 生成 .blend/.pngcesium.blend 导出 .glb/.json,并生成 Cesium 预览 HTML。preview 只在已有 .glb/.json 时补生成 HTML。reimport 把手工编辑过的 GeoPackage 回导为 GeoJSON不含在 all 里,详见 QGIS 手工修正工作流

区域配置

新区域从模板复制:

cp config/examples/template.json config/areas/my-area.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": ""
  }
}

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 覆盖:

{
  "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"
  }
}

预览 Cesium 页面时,需要在输出目录启动 HTTP 服务,避免浏览器拦截本地文件请求:

cd outputs/my-area
python3 -m http.server 8765

然后打开 http://localhost:8765/my-area-cesium-preview.html

实验:车辆巡航

previewcesium 阶段会额外生成 <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 阶段,可以直接运行:

npm run build:qgis -- --config config/hanyang-block.json

Blender 低层命令:

/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

Cesium GLB 低层导出:

/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

QGIS 手工修正工作流

如果已经在现成的 .qgz 项目里直接编辑了 gpkg 图层,不要再重跑 intermediates,否则会把手工修改覆盖掉。推荐流程是:

  1. 在 QGIS 中打开 outputs/<area-id>/<area-id>.qgz
  2. 直接编辑项目内关联的 gpkg 图层并保存
  3. reimport 回导 GeoJSON 并重建场景,再接 blender,cesium

南台子湖创新谷当前可直接使用下面这条命令:

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 字节文件,直接覆盖会静默损坏数据)
  • intermediatesreimport 互斥,同时指定会直接报错:前者用 OSM 重建 gpkg,正好会抹掉后者要读回的手工修改
  • blender,cesium 阶段读取的是 osm2streets_web_out/*.geojson,不是直接读取 gpkg
  • 如果 Blender 当前环境不稳定,先确认 geojson 已完成回导,再单独排查 Blender 本身
  • 增删图层或调整 z_index 只需改 scripts/lib/scene-layers.js构建、场景合并、场景样式、QGIS 工程会一并同步

文档

Description
No description provided
Readme 82 MiB
Languages
Python 60.9%
JavaScript 32%
HTML 6.7%
CSS 0.4%