Files
osmWorkflow/blender
que01 24e02e2041 refactor: 抽 osmassets 包,要素注册表,材质单一定义源 (P0-P3)
generate_scene.py 从 1271 → 816 行 (-455)

P0: 纯函数搬家
- osmassets/osm.py: parse_osm / Projector / parse_height
- osmassets/geom.py: clip_polygon / point_in_polygon / distance_to_ring / sample_tree_row 等
- blender/tests/test_pure.py: 42 个 unittest (脱离 bpy 运行)

P1: 单一定义源
- osmassets/catalog.py: ROAD_LAYERS + MATERIALS (含 cesium 导出参数)
- 对接 osm2streets_scene_style.json 做图层一致性 warning
- 干掉 road_mats / layer_z / 材质参数三份副本

P2: 要素注册表
- osmassets/{water,grass,scrub}.py: 每个要素一个 assemble() 函数
- build() 中的 if/elif 链收缩为注册表调用
- 计数器集中到 counts 字典

P3: 材质契约化
- catalog.py 扩展 CESIUM_EXPORT 段 (tint/metallic/emission)
- 标记已发现的死条目 Office White Metal Facade (四表各一组)

校验:
- parity.js + scene_digest.py + glb-digest.js 三位一体
- control-1 vs p0/p1/p2a/p2b/p3-counts: 两区域全 PARITY OK
- 42 个纯 Python 测试全部通过

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 17:59:32 +08:00
..
2026-07-29 14:46:29 +08:00

Blender 3D 场景生成

该生成器将 OSM 建筑、水体、植被标签,以及可选的 osm2streets GeoJSON 道路图层,组合为 Blender 3D 场景。

项目主入口是根目录的区域管线:

npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages blender,cesium

下面的命令适合单独调试 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/output.blend" \
  --render "/path/to/preview.png" \
  --tree-style natural

--geojson 为可选参数。不提供时,道路使用简单的 OSM highway 折线,而非详细 osm2streets 几何。实际资产生成建议先跑 intermediates 阶段,为 Blender 提供 osm2streets 道路面、标线、斑马线和箭头。 --tree-style 可选 naturalprocedural。默认 natural 使用低面数树干和多层不规则树冠,形态比球形程序化树冠更自然,渲染也比外部 OBJ 树模型轻;procedural 最轻但更卡通。

使用 --office-overrides 指定一组 OSM way ID逗号分隔这些建筑将渲染为办公楼风格即使其 OSM 标签为 building=industrial

  --office-overrides "117753521,117753535"

说明

  • OSM bounds 元素定义场景范围(排除远处的地铁等关系成员)
  • natural=tree 节点 → 独立树木(默认低面数自然树冠)
  • natural=tree_row 路径 → 沿路径均匀分布的树木
  • landuse=grass → 绿色地面
  • natural=scrub → 低矮灌木丛
  • amenity=fountain → 低多边形喷泉
  • 建筑:building=industrial → 厂房风格;其他 → 办公楼风格(带窗带)
  • 植被和建筑高度从 OSM height 标签读取
  • 程序化细节(窗带、屋顶设备、树冠)不改变 OSM 体量
  • 纹理使用 Poly Haven 的 1K CC0 纹理,打包在 .blend

导出为 Cesium GLB

/Applications/Blender.app/Contents/MacOS/Blender \
  --background \
  --python blender/export_cesium.py -- \
  --blend "/path/to/output.blend" \
  --glb "/path/to/output_cesium.glb" \
  --metadata "/path/to/output_cesium.json"

GLB 使用以 OSM bounds 中心为原点的局部 ENU 坐标系X 东Y 北Z 上)。 使用配套的 JSON 元数据文件将模型放置到 Cesium 中。 区域管线的 cesium 阶段还会在输出目录生成 <area-id>-cesium-preview.html

导出脚本会:

  • 应用网格修改器并创建 UV
  • 将 Blender 特有材质转换为 glTF 兼容 PBR 材质
  • 烘焙色调覆盖基础色以实现干净的 Web 渲染
  • 将所有纹理图片嵌入 GLB
  • 写入包含 WGS84 锚点和 Cesium JS 辅助代码的 JSON 元数据

预览

在输出目录上启动 HTTP 服务后打开预览页:

cd /path/to/output
python3 -m http.server 8765