经纬志
首页 / 实战手册 / MapLibre 样式与图层

setTerrain 之后地面还是平的

先看结论

按照文档加了地形源,倾斜视角后山脉毫无起伏,建筑也没有跟着贴到坡面上。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

map.setTerrain({ source: 'terrain', exaggeration: 1.5 }) 执行成功, 但画面没有高度变化。map.getTerrain() 返回对象,说明配置已被接受。 有时控制台报:

Error: Source "terrain" cannot be used as terrain because it is not a raster-dem source.

原因

原因表现
源类型写成 raster直接报上述错误
encoding 与数据不匹配不报错,地形几乎为 0 或出现巨大尖刺
DEM 瓦片 tileSize 写成 512高程被错误插值,起伏很浅
maxzoom 小于当前缩放远处有起伏,近处反而平坦
视角是垂直俯视视觉上看不出高度差

encoding 有两个取值:terrarium 与 mapbox。 两者解码公式不同,用错时高程会被算成几十米到几千米的偏差。

排查过程

先确认源类型和编码,再确认是否真的取到了瓦片:

var src = map.getSource('terrain');
console.log('源类型', src.type);
console.log('地形配置', map.getTerrain());
map.on('error', function (e) { console.error(e.error && e.error.message); });

用瓦片地址单独下载一张 DEM,检查 PNG 的尺寸与像素值。 256×256 对应 tileSize: 256,512×512 对应 512,不能凭经验填。

解决方案

明确声明 raster-dem、编码与瓦片尺寸,并给足最大级别:

map.addSource('terrain', {
  type: 'raster-dem',
  tiles: ['https://dem.example.cn/{z}/{x}/{y}.png'],
  encoding: 'terrarium',      // 按数据生产方确认
  tileSize: 256,
  minzoom: 0,
  maxzoom: 12,
  attribution: 'DEM © Example'
});

map.setTerrain({ source: 'terrain', exaggeration: 1.5 });

地形生效后,倾斜视角才能看出来。给一个初始俯仰角,避免用户以为没加载:

map.setPitch(55);
map.setBearing(20);

建筑需要贴地时,给 fill-extrusion 图层打开垂直贴地:

map.addLayer({
  id: 'buildings-3d',
  type: 'fill-extrusion',
  source: 'buildings',
  paint: {
    'fill-extrusion-height': ['get', 'height'],
    'fill-extrusion-base': ['get', 'min_height'],
    'fill-extrusion-color': '#c9d3dd',
    'fill-extrusion-opacity': 0.9
  }
});

验证

把 exaggeration 从 1 调到 2,同一机位下山体轮廓明显变化。 在地形起伏大的区域,建筑底部与坡面贴合,不出现悬空。 map.getTerrain() 的 source 与设置一致。

先确认编码:同一份 DEM 用错 encoding,画面会变成 “整体像平地”或“到处是尖刺”两种极端,都不会报错。 向数据提供方确认编码,比反复调 exaggeration 有效。

引用本文

经纬志(2026)。《setTerrain 之后地面还是平的》。https://www.jingweizhi.com/cookbook/maplibre-terrain-not-work.html(访问日期 2026-11-03)。