经纬志
首页 / Cesium / 教程

地形与影像图层

先看结论

影像决定球体表面「长什么样」,地形决定球体表面「有多高」。两套瓦片各自请求、 各自调度,只开其中一个也能正常显示,但两者的高度基准必须一致。

最后验证 2026-11-03 · CesiumJS 1.121 · 更新 2026-10-27 · 引用本文

影像图层是有序集合

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对应的服务标准说明
UrlTemplateImageryProviderXYZ / TMS 风格地址模板最通用,{z}/{x}/{y} 占位,国内底图多用它
WebMapServiceImageryProviderOGC WMS参数是 layers 与 parameters,注意 crs 与 version
WebMapTileServiceImageryProviderOGC WMTS需要 layer、style、tileMatrixSetID
ArcGisMapServerImageryProviderArcGIS MapServer可用 fromBasemapType 直接取内置底图
TileMapServiceImageryProviderTMS 目录fromUrl 会读取 tilemapresource.xml
SingleTileImageryProvider单张图片适合示意图、规划图,图片被拉伸到指定 rectangle
IonImageryProviderCesium 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。

影像和地形对不上时的排查顺序

  1. 确认影像是否真的加载:打开网络面板,看瓦片请求是否返回 200。
  2. 确认地形服务是否返回 quantized-mesh 瓦片,而不是 HTML 错误页。
  3. 确认两者用的是同一套坐标系。影像做了 GCJ-02 偏移而地形没有,山和路就会错开。
  4. 确认高度基准。把 terrainExaggeration 临时设回 1,看模型是否仍悬空。
引用本文

经纬志(2026)。《地形与影像图层》。https://www.jingweizhi.com/cesium/tutorial/terrain-imagery.html(访问日期 2026-11-03)。