模型悬空或陷进地形,差的那几米在哪
坐标填的是地面点,模型却飘在半空十几米;换成另一个视角,又有一半埋进了山体。

现象
同一份 model.glb,在没有地形时贴地正常,打开世界地形后底部悬空约 8 米;
换到山区,模型下沿被地形切掉一半。打印 position 的经纬度和高度,
数值与设计图上的点位完全一致。
原因
这里叠了三个独立因素:
| 因素 | 表现 | 量级 |
|---|---|---|
| 模型原点不在底面 | 整体上浮或下沉 | 等于模型包围盒的最小 Y |
| 高度写死为 0 | 地形抬高后陷进去 | 当地地形高程,几十到几百米 |
| 地形夸张系数 | 同一坐标在两套地形下位置不同 | terrainExaggeration 倍数 |
heightReference 只在实体位置的高度为 0 时才按地表贴合,
如果模型自身原点在体块中心,贴地之后仍然有一半在下面。
排查过程
先量模型自身:加载完成后读包围球,算出最低点相对原点的偏移。
var entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(116.391, 39.907, 0),
model: { uri: '/models/tower.glb' }
});
viewer.scene.globe.tilesLoaded = true;
entity.model.readyPromise.then(function (model) {
var bs = model.boundingSphere;
console.log('包围球半径', bs.radius);
console.log('中心相对原点', Cesium.Cartesian3.subtract(
bs.center, entity.position.getValue(viewer.clock.currentTime), new Cesium.Cartesian3()
));
});
再量地面:不要在 Viewer 构造完立刻采样,此时地形瓦片还没到。
等 globe.tilesLoaded 为真,或用 sampleTerrainMostDetailed
主动请求该点的高程。
var terrain = await Cesium.createWorldTerrainAsync();
var carto = Cesium.Cartographic.fromDegrees(116.391, 39.907);
var samples = await Cesium.sampleTerrainMostDetailed(terrain, [carto]);
console.log('地面高程', samples[0].height);
解决方案
方案一:让 Cesium 负责贴地,同时把模型原点偏移掉。适合原点在底面的模型:
var position = Cesium.Cartesian3.fromDegrees(116.391, 39.907, 0);
viewer.entities.add({
position: position,
model: {
uri: '/models/tower.glb',
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
minimumPixelSize: 48
}
});
方案二:自己算高度,把模型最低点压到地面上。适合需要精确控制、或原点在中心的模型:
var groundHeight = samples[0].height;
var bottomOffset = -12.4; // 包围盒最低点,加载后实测得到
var placeHeight = groundHeight - bottomOffset;
var matrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(116.391, 39.907, placeHeight)
);
var model = viewer.scene.primitives.add(
Cesium.Model.fromGltf({ url: '/models/tower.glb', modelMatrix: matrix })
);
方案三:如果地形开了夸张,把 terrainExaggeration 与模型高度一起调整,
否则模型会随地形被拉伸而再次错位。
viewer.scene.globe.terrainExaggeration = 1.0; // 先归零核对,再决定是否开启
可运行示例
复现器保留了本页的故障输入:坐标填的是地面点,模型却飘在半空十几米;换成另一个视角,又有一半埋进了山体。点「修复后」可以看到同样的输入在正确配置下的结果。
修复后:方案一:让 Cesium 负责贴地,同时把模型原点偏移掉。适合原点在底面的模型:
验证
在模型底部加一个 heightReference: CLAMP_TO_GROUND 的小圆点作为基准,
切换 2D/3D 视角观察,圆点与模型底面应始终重合。
把相机降到贴近地面,模型底部与地形之间不应出现可见缝隙或穿插。
常见误判:在 viewer 创建后立刻用 scene.sampleHeight
取高度,拿到的是椭球面高度 0,而不是地形高度。必须等地形瓦片加载,或改用
sampleTerrainMostDetailed。
经纬志(2026)。《模型悬空或陷进地形,差的那几米在哪》。https://www.jingweizhi.com/cookbook/cesium-model-float-sink.html(访问日期 2026-11-03)。