Cesium中高度采样方法总结
Cesium 高度采样 API 全解析
在 Cesium 三维应用开发中,经常会遇到高度采样,以及批量加载贴地、贴模型的 Label、Billboard、模型等需求。
Cesium 中常用的高度采样 API 有 5 个:
globe.getHeightCesium.sampleTerrainCesium.sampleTerrainMostDetailedscene.sampleHeightscene.sampleHeightMostDetailed
它们看起来都在“获取高度”,实际分属两套体系:
- TerrainProvider 地形线:只采样 TerrainProvider 提供的地形高度。
- Scene 场景线:采样 Globe、3D Tiles 等场景几何表面。
理解这两条线,再搞清楚各自的 LOD 策略,基本就知道该怎么选了。

五种 API 简介
globe.getHeight
1 | const carto = Cesium.Cartographic.fromDegrees(116.39, 39.9) |
globe.getHeight 直接查询 Globe 当前已经加载的地形瓦片,不会主动向 TerrainProvider 请求新的瓦片。
源码中,它会根据目标经纬度沿地形瓦片树向更细层级查找,尽可能使用当前已有的最细 terrain mesh,再通过 tile.data.pick(...) 与地形三角网求交得到高度。
因此,它的精度取决于当前已经加载的地形 LOD:
- 细瓦片已加载:得到更精细的高度;
- 只有粗瓦片:得到对应粗 LOD 的高度;
- 没有可用 terrain mesh:返回
undefined。
同步、快、不发起额外瓦片请求,但不保证最高精度。
Cesium.sampleTerrain
1 | const positions = [ |
sampleTerrain 会主动向 TerrainProvider 请求指定 Level 的地形瓦片,并基于该层级的地形三角网采样高度。上面的 12 就是指定的 Terrain Level。
它适合需要主动加载地形、但不需要最高可用 Level 的场景,开发者可以自行控制采样精度和请求成本。
Cesium.sampleTerrainMostDetailed
1 | const positions = [ |
sampleTerrainMostDetailed 可以看作 sampleTerrain 的自动选级版本:Level 不再由开发者指定,而是根据 TerrainProvider 的 availability 确定每个位置的最高可用 Level,再进行地形采样。
它只处理 TerrainProvider,不会采到建筑、倾斜摄影等 3D Tiles 表面。
scene.sampleHeight
1 | const carto = Cesium.Cartographic.fromDegrees(116.39, 39.9) |
和前面的 Terrain API 不同,sampleHeight 查询的是 Scene 中的场景表面。
对于 Globe tiles 和 3D Tiles,它使用当前视图中已经渲染的瓦片,不会为了这次查询主动把 3D Tiles 加载到最大 LOD。其他可拾取 primitives 的可见性规则与 Globe / 3D Tiles 不完全相同。
因此它很适合鼠标点击、即时贴地等交互场景。
scene.sampleHeightMostDetailed
1 | const positions = [ |
sampleHeightMostDetailed 是 Scene 系列的异步高精度版本。
它会为 Most Detailed Picking 准备所需的 3D Tiles 内容,在高精度瓦片就绪后再执行场景表面采样。
MostDetailed官方明确强调的是对 3D Tilesets 使用 maximum level of detail,不要理解成 Terrain 和 3D Tiles 都会主动加载到各自最高 LOD。
五种 API 的区别

API 怎么选
场景一:鼠标点击、即时高度查询
需要当前场景表面:
1 | const height = viewer.scene.sampleHeight(carto) |
只有地形,并且只关心当前已加载的地形高度:
1 | const height = viewer.scene.globe.getHeight(carto) |
这类交互通常追求响应速度,没有必要主动加载最高 LOD。
场景二:3D Tiles 批量贴模型、贴地
需要采样建筑、倾斜摄影等 3D Tiles 的高精度表面:
1 | const updatedPositions = |
传入的 positions 会被原地更新;如果某个位置无法采样,对应元素可能为 undefined。
场景三:TerrainProvider 最高可用 Level 采样
只关心地形,并希望采样每个位置的最高可用 Terrain Level:
1 | await Cesium.sampleTerrainMostDetailed( |
场景四:TerrainProvider 大批量固定精度采样
如果点位很多,又不需要最高可用 Level:
1 | await Cesium.sampleTerrain( |
指定 Level 可以在精度、瓦片请求量和采样成本之间做取舍。
场景五:地形 + 倾斜摄影 + 建筑混合场景
关键是先确定想采什么表面:
- 想贴建筑、倾斜摄影等场景表面:选择
sampleHeight系列; - 只想获取 TerrainProvider 地形:选择
sampleTerrain系列; - 是否使用
MostDetailed,再根据 LOD 需求决定。
如果只是想让 Scene 系列忽略少量已知对象,可以使用 objectsToExclude。
💣 几个容易踩的坑
1. sampleHeightMostDetailed 不保证地形最高 LOD
sampleHeightMostDetailed 的 MostDetailed 针对 3D Tiles:源码会通过 MOST_DETAILED_PRELOAD 准备所需的最大 LOD 3D Tiles,但不会像 sampleTerrainMostDetailed 那样,根据 TerrainProvider.availability 查找并请求最高可用 Terrain Level。
因此:
- 3D Tiles 最大 LOD 表面 →
sampleHeightMostDetailed - Terrain 最高可用 Level →
sampleTerrainMostDetailed
即使场景中只有 Terrain,sampleHeightMostDetailed 也不等于最高可用 Level 的地形采样。
2. Cartographic.height 不一定直接等同于“海拔”
Cesium 的 Cartographic.height 在坐标模型中表示相对于参考椭球面的高度。但对于 sampleTerrain 等 API,最终采样到的数值还与 TerrainProvider 所使用的地形数据及其垂直基准有关。
如果业务对“海拔”“正高”“椭球高”有严格要求,需要确认地形数据的垂直基准,必要时进行 Geoid / 垂直基准转换。
🔬 本地源码验证
以下基于本机 gis-template 项目的 node_modules/cesium@1.136.0 核对。不同 Cesium 版本的打包行号可能变化,建议直接搜索函数名。
| 结论 | 源码入口 | 关键点 |
|---|---|---|
globe.getHeight 基于当前地形 mesh 求交 |
Globe.prototype.getHeight |
不主动请求新瓦片 |
sampleTerrain 采样指定 Level |
sampleTerrain |
参数显式传入 level |
sampleTerrainMostDetailed 查找最高可用 Level |
sampleTerrainMostDetailed |
依赖 TerrainProvider availability |
sampleHeight 获取 Scene 表面高度 |
Picking.prototype.sampleHeight |
Globe / 3D Tiles 使用当前视图中已渲染内容 |
sampleHeightMostDetailed 执行 Most Detailed Picking |
Most Detailed picking 相关逻辑 | 对 3D Tilesets 使用 maximum LOD |
sampleHeight 依赖 depth texture |
Scene#sampleHeight JSDoc |
通过 sampleHeightSupported 判断支持情况 |
总结
如果只想记住一张表:
| 需求 | API |
|---|---|
| 当前已加载的地形高度 | globe.getHeight |
| 指定 Terrain Level | sampleTerrain |
| 最高可用 Terrain Level | sampleTerrainMostDetailed |
| 当前 Scene 表面高度 | sampleHeight |
| Scene + 3D Tiles 最大 LOD | sampleHeightMostDetailed |
拓展:clampToHeight
如果需求不是“获取一个 height”,而是直接把 Cartesian3 点贴到场景表面,还可以使用:
scene.clampToHeightscene.clampToHeightMostDetailed
它们和 sampleHeight / sampleHeightMostDetailed 属于相近的一组 API,输入输出使用 Cartesian3,适合直接处理 Entity、Primitive 或模型的位置。
官方文档
- Scene:https://cesium.com/learn/cesiumjs/ref-doc/Scene.html
- Globe:https://cesium.com/learn/cesiumjs/ref-doc/Globe.html
sampleTerrain/sampleTerrainMostDetailed:https://cesium.com/learn/cesiumjs/ref-doc/global.html
先确定采地形还是采场景,再确定需要什么 LOD,这 5 个 API 就很好选了。


