fix: 修正 Cesium 巡航车道中心对齐

This commit is contained in:
2026-08-08 15:21:49 +08:00
parent aeb2cec021
commit 5658e7337d
17 changed files with 1081 additions and 192 deletions

View File

@@ -205,6 +205,28 @@ tilt_y = TILT_JITTER * math.cos(index * 0.927295)
模型保持在**局部 ENU 坐标系**X 东、Y 北、Z 上),靠伴生 JSON 配合
`Cesium.Transforms.eastNorthUpToFixedFrame` 摆放。
### WGS84 ENU 坐标契约
Blender 中所有经纬度几何必须通过 `osmassets.osm.Projector` 转换。该转换必须与 Cesium
`eastNorthUpToFixedFrame(anchor)` 使用同一个 WGS84 椭球语义:先将经纬度转换为
ECEF再将相对锚点的向量投影到 East/North 轴。禁止用固定 `111320 m/deg`
equirectangular等距圆柱近似生成场景坐标。
固定米/度近似只会在锚点附近碰巧重合;纬向比例与 WGS84 实际比例不同,误差会随离锚点
距离增长。表现为 Cesium Entity 路线在部分道路居中、在其他道路相对整个 GLB 路面同向
平移。只验证 route 与 GeoJSON 自洽无法发现此问题,必须重新生成
`blender,cesium,preview` 并在最终 Cesium 画面中核对。
修改 `Projector` 后至少执行:
```bash
python3 -m unittest blender.tests.test_pure
npm run build:area -- --config config/areas/<area>.json --stages blender,cesium,preview
```
`blender.tests.test_pure.ProjectorTest` 必须断言锚点为原点、East/North 方向正确,以及局部
经纬度增量符合 WGS84 椭球曲率半径。
### Cesium contract
新生成场景的 Cesium 导出调色写在 `catalog.MATERIALS[*]["cesium"]`,由
@@ -278,6 +300,7 @@ tilt_y = TILT_JITTER * math.cos(index * 0.927295)
| 直接 append vendored 资产的材质 | alpha-clip 缺失,树冠渲染成一块 |
| 删掉"试过不行"的注释 | 下一个人重新踩同一个坑 |
| 从 `scene-layers.js` 的 hex 换算 Blender 颜色 | 抹掉独立调过的配色 |
| 用固定米/度比例投影经纬度 | GLB 与 Cesium Entity 随离锚点距离产生位置漂移 |
| 加新资产不配 Cesium 调色 | Cesium 里显得发黑 |
| 靠调 `FOLIAGE_EMISSION` 提亮植被 | 用错了旋钮,该调 albedo gain |
| 在 `MATERIALS` 中间插入条目 | GLB 材质索引整体平移 |

View File

@@ -46,6 +46,7 @@ cesium-preview.js 浏览器
- [ ] 你在改任何被 `execFileSync` / `spawnSync` 调起的东西
- [ ] 你在改 stage 的 stdout 打印
- [ ] 你要新增一种在 Blender 里生成、要在 Cesium 里看的资产
- [ ] Blender GLB 与 Cesium Entity、polyline 或 label 必须在地理位置上重合
---
@@ -161,6 +162,19 @@ OSM way 的端点不一定在原始 XML 中有三个以上相连 wayosm2stree
**教训****跨阶段运行时 JSON 必须在最早消费它的 stage 从当前权威产物重建;同时要
区分“初始化来源”和“编辑后的事实源”,不能用早期输入覆盖人工编辑。**
### 坑 7GeoJSON 内部正确,但 GLB 与 Cesium 路线仍然错位
巡航路线曾经与 osm2streets Driving polygon 中轴逐点吻合到厘米级,仍在最终预览中出现
部分路段偏离车道中心。原因是路线由 Cesium 直接按 WGS84 经纬度放置,而 Blender GLB
使用固定 `111320 m/deg` 的近似投影后再放到 WGS84 ENU 锚点。两套坐标仅在锚点附近
重合,误差随距离增长。
**教训**:跨坐标运行时不能只验证源数据内部自洽。凡是 Blender GLB 与 Cesium Entity
需要重合,必须检查 `GeoJSON -> Blender local ENU -> GLB modelMatrix`
`GeoJSON -> Cesium Cartesian3` 的端到端契约,并在最终画面做横截面对齐验证。
→ [资产生成WGS84 ENU 坐标契约](../blender/asset-generation.md#wgs84-enu-坐标契约)
---
## 加东西时的检查清单

View File

@@ -746,6 +746,9 @@ runtime 与 HTML并写 preview manifest。预览内容实现不得回流到
- `inputs.osm`
- `inputs.glb`
- `inputs.metadata`
- `inputs.lanePolygons`
- `inputs.network`
- `inputs.intersectionSurface`
- `inputs.previewCss`
- `inputs.previewJs`
- `outputs.cesiumPreview`

View File

@@ -112,6 +112,9 @@ setLoadingMessage("Preparing view")
window.osmPreview = { viewer, metadata, placement, assets, cruise, cameras };
```
预览加载的生成式 JSON路线和交通信号使用 `fetch(..., { cache: "no-store" })`,因为
这些文件保持稳定文件名但会被单独重生成;浏览器不得继续显示旧的巡航路线。
调试和无头检查都靠它。**加新的顶层对象就往这里挂**,不要再开新全局。
---

View File

@@ -11,9 +11,9 @@
## 2. Signatures
```js
buildVehicleRoute(osmPath) => {
source, bounds, generatedAt, speedMetersPerSecond, loop,
routes, segments
buildVehicleRoute(osmPath, lanePolygonsPath, networkPath, intersectionSurfacePath) => {
source, laneSource, networkSource, intersectionSource, bounds, generatedAt, speedMetersPerSecond, loop,
routes, segments, diagnostics
}
allowedTurns(tags, direction) => Set<"left" | "through" | "right">
@@ -28,7 +28,14 @@ classifyConnection(incomingEdge, outgoingEdge) =>
- `routes` 是当前主字段;`segments` 必须是同一数组的兼容别名,供旧预览使用。
- 每个路线至少包含 `id``coordinates``centerlineCoordinates``lengthMeters`
`maneuvers``edgeIds``coordinates` 是右侧车道偏移后的闭合巡航轨迹
`maneuvers``edgeIds``laneSegments``connectors`。道路区间来自匹配的 Driving lane polygon 中轴
- 路线拓扑以 `network.json` 的 internal road 和 intersection 为准;禁止把整个 OSM way 直接当作一条不可分割 edge。
- connector 必须绑定同一个 internal intersection并位于对应 `intersection_surface.geojson` 内或允许的边界容差内;越界时拒绝候选路线。
- preview 必须将 `lane_polygons.geojson``network.json``intersection_surface.geojson` 作为强制输入;缺失或无效时在写产物前失败。
- route 经纬度由 Cesium 按 WGS84 直接放置;最终道路 GLB 必须由 WGS84 ECEF→ENU
`Projector` 生成。禁止以固定米/度近似投影道路,否则即使 route 与 lane polygon
完全一致,最终画面仍会随离锚点距离产生横向偏移。
- 单条路线无法可靠匹配时跳过并写结构化 `diagnostics`,不得回退固定或默认车道宽度。
-`oneway=yes`(及等价真值)的 way 只能按 OSM 原始方向生成 edge绝不能生成反向
`:backward` edge`oneway=-1` 仅允许反向 edge。
- 去程在路口按入边方向读取 `turn:lanes:forward``turn:lanes:backward`,只有标签中的
@@ -36,6 +43,7 @@ classifyConnection(incomingEdge, outgoingEdge) =>
- 返程是展示路线的原路回返,不以反向 `turn:lanes` 再次否决,但依旧不可逆行单行道。
- 路网没有闭环时,在去程和返程端点插入平滑调头曲线;不得在 way 端点或路口瞬移。
- 选择菜单使用 `#编号 · 长度 m · 左 N / 右 N / 直 N`,因为一条路线可跨越多个道路名称。
- 预览只显示当前下拉框选中车辆的 route polyline避免多条闭环轨迹在路口重叠造成错误的偏移判断。
## 4. Validation & Error Matrix
@@ -62,6 +70,8 @@ classifyConnection(incomingEdge, outgoingEdge) =>
`node --check scripts/lib/cesium-preview.js`:保证 Node 与浏览器直载脚本语法可用。
- 对目标区域运行 `npm run build:area -- --config config/areas/<area>.json --stages preview`,确认
`routes` 中存在左、右、直动作,且 Cesium 下拉标签显示编号、长度与动作统计。
- 修改地理投影时必须运行 `blender,cesium,preview`,不能只重跑 preview最终检查青色路线
到黄色中心线及道路边缘的横截面距离,确认两侧路线分别位于各自车道中心。
## 7. Wrong vs Correct