地形与影像图层
影像决定球体表面「长什么样」,地形决定球体表面「有多高」。两套瓦片各自请求、 各自调度,只开其中一个也能正常显示,但两者的高度基准必须一致。
影像图层是有序集合
viewer.imageryLayers 是一个 ImageryLayerCollection,
索引 0 在最下面,越往后越靠上。上层带透明度时会叠加显示下层,
因此顺序直接决定最终观感。
| 成员 | 作用 |
|---|---|
add(provider) | 添加到最上层 |
addImageryProvider(provider) | 同上,返回新图层 |
raise(layer) / lower(layer) | 上移或下移一层 |
raiseToTop(layer) / lowerToBottom(layer) | 直接置顶或置底 |
remove(layer, true) | 移除并销毁,第二个参数不要省 |
layer.alpha | 整层透明度,0 到 1 |
layer.brightness / contrast / saturation | 亮度、对比度、饱和度,用于不同来源的底图配色统一 |
layer.show | 是否显示该层,保留对象便于随时打开 |
layer.splitDirection | 卷帘对比,配合 scene.splitPosition |
var layers = viewer.imageryLayers;
var grid = layers.add(new Cesium.GridImageryProvider({
color: Cesium.Color.WHITE.withAlpha(0.4),
glowColor: Cesium.Color.TRANSPARENT,
backgroundColor: Cesium.Color.fromCssColorString('#16324a').withAlpha(0.5),
cells: 4
}));
grid.alpha = 0.6;
layers.raiseToTop(grid);
GridImageryProvider 不请求任何网络资源,纯程序生成网格,适合调试瓦片范围。
同类的还有 TileCoordinatesImageryProvider,会把每块瓦片的行列号画在瓦片上。
常用的影像来源
| Provider | 对应的服务标准 | 说明 |
|---|---|---|
UrlTemplateImageryProvider | XYZ / TMS 风格地址模板 | 最通用,{z}/{x}/{y} 占位,国内底图多用它 |
WebMapServiceImageryProvider | OGC WMS | 参数是 layers 与 parameters,注意 crs 与 version |
WebMapTileServiceImageryProvider | OGC WMTS | 需要 layer、style、tileMatrixSetID |
ArcGisMapServerImageryProvider | ArcGIS MapServer | 可用 fromBasemapType 直接取内置底图 |
TileMapServiceImageryProvider | TMS 目录 | fromUrl 会读取 tilemapresource.xml |
SingleTileImageryProvider | 单张图片 | 适合示意图、规划图,图片被拉伸到指定 rectangle |
IonImageryProvider | Cesium ion | 需要 token,离线部署的项目避免使用 |
瓦片协议的三个必查项:坐标系是否 Web Mercator(EPSG:3857)、
行列号的起点是从 0 还是从 1、y 轴是否翻转。
这三项任意一项不对,画面会出现错位或空白瓦片,且不会有报错。
地形是另一条管线
Viewer 的 terrainProvider 决定高程数据来源。默认是
EllipsoidTerrainProvider,也就是一个光滑椭球面,高度恒为 0。
// 自建的 quantized-mesh 地形服务
var terrain = await Cesium.CesiumTerrainProvider.fromUrl(
'https://your-host/terrain/',
{ requestVertexNormals: true, requestWaterMask: false }
);
viewer.terrainProvider = terrain;
// 或者用程序生成的高度图,不需要任何服务
viewer.terrainProvider = new Cesium.CustomHeightmapTerrainProvider({
width: 32,
height: 32,
tilingScheme: new Cesium.GeographicTilingScheme(),
callback: function (x, y, level) {
var map = new Float32Array(32 * 32);
// 按 x、y、level 算出经纬度后填充高程
return map;
}
});
requestVertexNormals 让地形带上法线,开启光照后才有明暗起伏;
不开的话山体是一块平色,看着像纸片。
地形夸张
平原地区的真实起伏在几百公里的视距下几乎看不出来。把高度整体放大是常见做法, 线状工程(管线、公路选线)演示里几乎都会用:
viewer.scene.globe.terrainExaggeration = 3.0;
viewer.scene.globe.terrainExaggerationRelativeHeight = 0;
terrainExaggerationRelativeHeight 是夸张的基准高度:以这个高度为零点放大,
设成当地平均海拔可以避免整个地形上浮一大截。
深度测试与贴地
加了地形之后,贴地的点和标签默认仍然按椭球面绘制,会「穿」进山体。 开启下面这个开关,图元才会和地形做深度比较:
viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(103.86, 31.68, 0),
point: {
pixelSize: 8,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
},
label: {
text: '山腰站点',
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance: 0 // 关键:0 表示参与深度测试
}
});
disableDepthTestDistance 的默认值是 0,但大量示例里写成了
Number.POSITIVE_INFINITY,那会让标签永远浮在最前面。
需要被山体遮挡时就必须把它设回 0。
影像和地形对不上时的排查顺序
- 确认影像是否真的加载:打开网络面板,看瓦片请求是否返回 200。
- 确认地形服务是否返回 quantized-mesh 瓦片,而不是 HTML 错误页。
- 确认两者用的是同一套坐标系。影像做了 GCJ-02 偏移而地形没有,山和路就会错开。
- 确认高度基准。把
terrainExaggeration临时设回 1,看模型是否仍悬空。
经纬志(2026)。《地形与影像图层》。https://www.jingweizhi.com/cesium/tutorial/terrain-imagery.html(访问日期 2026-11-03)。