做实景三维交付时,最常见的现场吐槽不是「模型糊」,而是「进 Cesium / 三维地球后飘了几米甚至几十米」。下面按排查顺序写一套可复用的核对清单,避免一上来就重切瓦片。
1. 先确认:飘移是「整体平移」还是「局部扭曲」
| 现象 | 更可能的原因 | 优先动作 |
|---|---|---|
| 整块模型相对底图平移,旋转看起来正常 | SRS / 原点 / ENU 原点不一致 | 核元数据与地球椭球参数 |
| 边角翘起、近处准远处歪 | 投影带号、中央经线选错 | 核对投影 EPSG 与测区经度 |
| 只有某一级瓦片偏 | 该层 tileset.json 或路径错乱 |
查 content.uri 与相对路径 |
整体平移优先别重切;局部扭曲才考虑重投影或重生成。
2. 打开元数据:SRS 与 transform 比肉眼对齐更准
OSGB / 3D Tiles 常见元数据位置:
- 根目录或 Data 旁的
metadata.xml、metadata.json tileset.json里的asset、root.transform、boundingVolume- 部分厂商会把 ENU 原点写在
SRSOrigin/origin字段
核对三件事:
- EPSG / WKT 是否与现场控制点一致(常见混用 CGCS2000 与 WGS84 经纬度)。
- 原点是否是「工程局部 ENU」 :有原点时,Cesium 要用对应的
modelMatrix或heightReference策略,不能直接当 ECEF 塞进去。 - 高程基准:椭球高 vs 正常高混用,会出现「平面看起来差不多、高度差一两米」的假对齐。
示意(伪代码,强调顺序,不绑定某一 SDK 版本):
js
// 1) 读 tileset
const tileset = await Cesium.Cesium3DTileset.fromUrl('./tileset.json');
// 2) 若元数据给出 ENU 原点 (lon, lat, height),先建东-北-天矩阵
const origin = Cesium.Cartesian3.fromDegrees(lon, lat, height);
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
// 3) 再挂模型;不要先塞进 viewer 再凭感觉拖
tileset.modelMatrix = enu;
viewer.scene.primitives.add(tileset);
如果厂商已经把 root.transform 写成 ECEF,就不要再叠一层 ENU,否则等于平移两次。
3. 瓦片路径:相对路径断了也会「看起来像飘了」
加载失败或只显示一块时,浏览器控制台常有 404。检查:
tileset.json里content.uri是相对路径还是绝对路径- 发布到对象存储 / Nginx 后,大小写与中文目录是否被改写
- OSGB 转 3D Tiles 后,是否漏拷了某一级
Tile_+xxx_+yyy目录
建议本地先用静态服务器打开根 tileset.json,确认整棵树 200,再接到 Cesium。
4. 快速自检清单(交付前 5 分钟)
- 用同一套控制点,在 QGIS / Global Mapper 核对平面坐标(别只在三维球里目视)。
- 记录元数据里的 SRS、原点、高程基准,写进交付说明,避免二期「对不齐」扯皮。
- Cesium 里先关地形夸张与深度检测干扰,排除「看起来偏了其实是地形」。
- 若必须重投影:优先在切瓦片前统一到目标 SRS,而不是在前端硬扭
modelMatrix。
5. 和 DEM / DOM 套合时的额外注意
倾斜模型常要叠正射与 DEM。套合前保证:
- DOM、DEM、OSGB 同一水平基准;
- DEM 的 NoData 与采样分辨率不会把模型「顶飞」;
- 若 DOM 是投影坐标、模型是经纬度,先统一再叠,不要依赖前端临时换算。
你在工程里更常遇到的是「整体平移几米」还是「换带号后局部扭曲」?欢迎评论区甩一下元数据里的 SRS 字段(可打码坐标),一起对症。