三维模型悬空与切片偏移的排查顺序(附验证代码)
一、现象与复现条件
同一份倾斜模型,在 A 机器加载正常,到 B 机器悬空一截、朝向反转;影像切片整体偏移一段距离,矢量压不到路上。复现条件通常有三个共同点:换了机器、换了坐标系、换了数据目录。
这类问题最常见的误区是直接拖相机或反复试参数。相机只改变观察位置,不改变数据基准;在不统一的基准上反复调,会出现"调了模型切片又偏、调了切片模型又悬空"的循环。
二、先分清三类问题
- 源数据问题:坐标系定义错误、切片生成时范围或层级不对、模型本身带偏移。
- 接入参数问题:rectangle、tileMatrixSet、最小/最大层级、模型变换矩阵。
- 显示基准问题:地形开启与关闭、地形夸张、椭球高与海拔基准的差异。
三类的处理方式完全不同:第一类回源头,第二类改参数,第三类先统一基准再调显示。分不清类别,调哪一层都是碰运气。
三、固定排查顺序
建议按下面顺序走,不要跳步:
1)打印服务声明的范围与切片矩阵;
2)打印模型包围球中心,转成经纬高;
3)关闭地形,再打开地形,各看一次;
4)选一个明显地物做参照,量出水平偏移和垂直偏移;
5)把偏移量记录成数字,再决定调哪一层。
为什么先量化:没有数字,你无法判断一次调整是变好了还是碰巧对上了。记录"偏多少米、悬空多少米",比"感觉差不多"有用得多。
四、两段可直接用的验证代码
js
// 1) 影像服务声明的范围与切片矩阵
const provider = new Cesium.WebMapTileServiceImageryProvider({
url: '/proxy/wmts',
layer: 'base',
style: 'default',
format: 'image/jpeg',
tileMatrixSetID: 'EPSG:3857'
});
console.log('rectangle', provider.rectangle);
console.log('tileMatrixSet', provider.tileMatrixSet);
// 2) 模型包围球中心转经纬高
const center = Cesium.Cartographic.fromCartesian(model.boundingSphere.center);
console.log('lon/lat/height', Cesium.Math.toDegrees(center.longitude),
Cesium.Math.toDegrees(center.latitude), center.height);
// 3) 粗略估算水平偏移(米):取两个经纬点做距离
const from = Cesium.Cartographic.fromDegrees(116.30, 39.90);
const to = Cesium.Cartographic.fromDegrees(116.301, 39.90);
console.log('offset(m)', Cesium.Cartographic.getDistance(from, to));
代码做三件事:把服务声明的范围打印出来、把模型中心转成经纬高、把经纬差换算成米。先有可比较的数字,再决定调服务、调模型还是调基准。

五、三种处理方式与边界
-
回源头重做切片
最彻底,适合坐标系定义错误、切片范围或层级生成错误。成本最高,需要重新走一遍数据处理流程。
-
修改接入参数
适合服务地址、切片矩阵、范围声明不匹配。风险是参数影响全局,改之前要确认没有其他图层依赖同一份配置。
-
场景内纠偏
适合历史数据、一次性交付、源数据不便改动的场景。二维切片用水平面把手调经纬度;三维模型用三轴平移和三面旋转。结果写入图层参数,随项目保存。
边界要说清楚:场景内纠偏解决的是历史偏移和显示对齐,不修复源数据本身。源数据错误仍需回源头。

六、验证清单
- 偏移量已经量化,不是"看起来差不多";
- 调整后保存、重开、换机器,结果一致;
- 纠偏结果不依赖源机器的绝对路径;
- 其他图层没有被误改;
- 源数据未被修改;
- 确认问题属于历史偏移,而不是源数据错误。

七、结论
三维模型悬空和切片偏移,多数不是渲染问题,而是基准不统一。先分清源数据、接入参数、显示基准三类,再按固定顺序量化偏移,最后选择回源头或场景内处理。顺序对了,比在渲染层反复试参数省时间。
这篇只讨论排查方法,不涉及具体产品和项目。