mcpField
M
maplibre-terrain-patterns

maplibre-terrain-patterns

github.com/maplibre开发15550 次安装今天更新
代码仓库

关于 maplibre-terrain-patterns

maplibre-terrain-patterns 是配置 MapLibre GL JS 地形可视化的技能,讲解 raster-dem 数据源及编码选择,并涵盖阴影、分层设色、运行时等高线、3D 地形和性能考量。

主要功能

  1. 01配置 raster-dem 数据源与编码
  2. 02添加地形阴影和分层设色图层
  3. 03运行时生成等高线
  4. 04以 3D 地形显示高程
  5. 05考量地形渲染性能

适用场景

  1. 01为 MapLibre 地图添加高程可视化
  2. 02选择地形瓦片的编码格式
  3. 03排查地形平坦或变形问题
  4. 04选择动态或预计算地形图层

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/maplibre/maplibre-agent-skills --skill maplibre-terrain-patterns

安装后在 Claude Code 中输入/maplibre-terrain-patterns确认已加载。

详细介绍

MapLibre 地形模式

MapLibre GL JS 可以通过多种方式渲染地形:山体阴影(由高程数据生成的 2D 光照效果)、3D 地形(使用高程值和相机倾角的挤出网格)、高程着色(根据高程值直接着色)以及动态等高线(运行时生成的矢量等高线)。[1], [7] 这些方法通常会在同一张地图中结合使用,以创建丰富的地形可视化效果。

所有这些方法都使用 raster-dem 数据源,通常称为“地形瓦片”,它会将高程值编码到 PNG/WebP 像素值中。[1], [3]

还有一些传统上由 DEM 派生的地球观测分析图层,例如坡度、坡向和曲率。[11], [14] 需要这些图层时,通常会在 GIS 工作流中预先计算并作为栅格图层提供,而不是在 MapLibre 客户端侧计算。

何时使用此技能

  • 向 MapLibre 地图添加山体阴影、高程着色、等高线或 3D 地形
  • 选择 raster-dem 数据源并了解编码格式
  • 从 Mapbox 地形瓦片迁移到开放替代方案
  • 根据地形数据添加动态等高线
  • 自托管 raster-dem 格式的地形瓦片
  • 排查地形显示平坦、倒置或视觉效果异常的问题
DEM、raster-dem 和山体阴影之间的区别

数字高程模型(DEM)、raster-dem 和山体阴影是不同的概念,经常被混淆。

DEM 是一种栅格,每个单元都存储一个数值高程(例如以米为单位的 GeoTIFF)。[15], [17]

MapLibre 不会直接读取这些 GeoTIFF。首先要将高程编码为 RGB 瓦片(Terrain‑RGB 或 Terrarium),然后将其作为 raster-dem 数据源提供给 MapLibre。[5], [6] raster-dem 数据源始终表示每个像素的高程,并使用一种受支持的编码("mapbox" 或 "terrarium")进行解码。[1], [3]

在 MapLibre 中创建山体阴影(或高程着色、等高线或 3D 地形)时,关键的前提是选择并配置合适的 raster-dem 数据源;自行生成 DEM 瓦片需要大量计算,既困难又通常没有必要,因为已有免费的或商业的高质量地形服务可用。[4], [8]

何时使用预计算栅格(而非 raster-dem)

在许多情况下,直接使用在外部工作流中预先计算并导出为瓦片的地形可视化结果会更简单。这种情况下,应将瓦片配置为 raster 类型的数据源,而不是 raster-dem。

OpenTopography 或 Blender 等服务,以及标准 GIS 工作流(GDAL、QGIS、ArcGIS),都可以生成山体阴影和高程着色栅格,并能全面控制光照、纹理和色带。[14], [21] 坡度栅格和混合式“彩色晕渲”产品必须直接在这些工具中根据 DEM 创建。[11], [20]

其优势在于,只需极少配置图层和数据源,就能获得丰富的地形可视化效果;同时性能更佳,因为客户端只需绘制预渲染的瓦片。[14], [22]

其局限在于,这些栅格不包含编码后的高程值(Terrain-RGB/Terrarium),因此无法为 MapLibre 中的客户端侧山体阴影/高程着色、3D 地形或运行时等高线提供数据。[3], [23]

在以下情况下,预计算栅格是合适的选择:

  • 只需要将地形作为静态背景(地形底图、晕渲背景)。
  • 希望在不同平台上保持一致的制图效果,并且不需要 MapLibre 在客户端侧重新计算山体阴影或高程着色。
  • 希望避免 DEM 编码和 raster-dem 配置带来的复杂性。

需要使用依赖高程的 MapLibre 功能(通过 setTerrain() 实现 3D 地形、客户端侧山体阴影或高程着色、动态等高线)时,请将这些图层指向由 Terrain‑RGB 或 Terrarium 瓦片提供支持的 raster-dem 数据源,例如 AWS Terrain Tiles、Mapterhorn、Stadia Terrarium 或 MapTiler Terrain RGB。[1], [4]

raster-dem 源与编码

raster-dem 源提供以 PNG/WebP 像素值编码的高程数据。MapLibre 会读取像素颜色,并根据编码格式对应的公式将其转换为以米为单位的高程。[1], [3]

这是地形配置中 AI 最容易出错的关键点。 MapLibre 的默认编码是 "mapbox"(Mapbox Terrain‑RGB 公式),但许多主要的开放和免费 DEM 源(例如 AWS Terrain Tiles 和 Mapterhorn)使用 Terrarium 格式。[5], [6] 使用错误的编码会导致高程数据悄无声息地出错——地形可能显示为平坦、倒置或夸张失真,而且控制台不会报错。

编码公式常见来源
"terrarium"(R * 256 + G + B / 256) - 32768AWS Terrain Tiles、Mapterhorn、大多数开放源
"mapbox"(R * 256 * 256 + G * 256 + B) * 0.1 - 10000MapTiler terrain-rgb、Mapbox Terrain

Terrarium 和 Mapbox 公式由 Tilezen/Mapzen 地形处理流程和 Mapbox Terrain‑RGB 规范定义。[5], [6]

配置样式前,务必确认 DEM 源的编码。 编码是数据本身的属性,而非偏好设置。

{
  "terrain": {
    "type": "raster-dem",
    "url": "pmtiles://terrain.pmtiles",
    "tileSize": 512,
    "encoding": "terrarium"
  }
}
开放地形瓦片源
来源编码是否需要密钥说明
AWS Terrain TilesTerrarium否原始 Mapzen 数据集;s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png;全球覆盖;256px PNG;若浏览器未使用 CDN,速度可能较慢
MapterhornTerrarium否WebP PMTiles;512px;全球覆盖,最高 z12;由 NLnet 资助的开源项目;可通过单个文件自托管
Stadia Maps TerrariumTerrarium是(提供免费层级)托管服务;快速 CDN
MapTiler terrain-rgbMapbox是托管服务;快速 CDN
demotiles.maplibre.orgTerrarium否用于官方 MapLibre 示例;不适用于生产环境

生产环境中如需使用无需密钥的方案,推荐选择 Mapterhorn。[4], [8] 请参阅 Mapterhorn 了解可用的托管端点。提取和自托管请参阅 maplibre-pmtiles-patterns。

山体阴影图层

必须在地图样式的图层数组中定义 hillshade 图层,并引用 raster-dem 数据源。它不需要 map.setTerrain()——山体阴影和 3D 地形互相独立。

{
  "id": "hillshade",
  "type": "hillshade",
  "source": "terrain",
  "paint": {
    "hillshade-illumination-direction": 315,
    "hillshade-illumination-anchor": "map",
    "hillshade-exaggeration": 0.5,
    "hillshade-shadow-color": "rgba(30,40,80,0.45)",
    "hillshade-highlight-color": "rgba(255,240,200,0.4)",
    "hillshade-accent-color": "rgba(10,15,50,0.5)"
  }
}

hillshade-method 用于控制阴影算法(standard、basic、combined、igor、multidirectional);多方向山体阴影可以模拟来自多个方向的光线来柔化阴影,无需叠加多个图层。[9] 一些制图师会使用多个 hillshade-illumination-direction 值不同的山体阴影图层,来微调多方向阴影效果。[10]、[11] 这种方法可能会影响性能。

如需查看由 raster-dem 数据源驱动的基本山体阴影配置,请参阅添加山体阴影图层。

**影像底图的配色方案:**暖金色高光(rgba(255,240,200,0.4))和冷蓝紫色阴影(rgba(30,40,80,0.45))可以增强影像对比度,同时避免叠加层显得灰暗浑浊。这是改编自 John Nelson 多遍渲染风格、适用于单个图层的配色方案。[10] 对于追求简洁外观的矢量底图,可使用中性灰色/白色高光和深色阴影。

动态等高线

maplibre-contour 可在运行时基于 raster-dem 数据源生成矢量等高线瓦片。无需预先生成等高线瓦片。[7]

import mlcontour from 'maplibre-contour';

const demSource = new mlcontour.DemSource({
  url: 'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png',
  encoding: 'terrarium',
  maxzoom: 13,
  worker: true
});

demSource.setupMaplibre(maplibregl);

map.on('load', () => {
  map.addSource(
    'contour-source',
    demSource.contourSource({
      thresholds: { 11: [200, 1000], 12: [100, 500], 14: [50, 200] },
      elevationKey: 'ele',
      levelKey: 'level',
      contourLayer: 'contours'
    })
  );

  map.addLayer({
    id: 'contours',
    type: 'line',
    source: 'contour-source',
    'source-layer': 'contours',
    paint: {
      'line-color': ['interpolate', ['linear'], ['get', 'level'], 0, '#8b6914', 1, '#5c4a00'],
      'line-width': ['interpolate', ['linear'], ['get', 'level'], 0, 0.8, 1, 1.5]
    }
  });
});

maplibre-contour 使用通过 setupMaplibre 注册的自定义协议处理程序。thresholds 对象将缩放级别映射到以米为单位的 [minor, major] 等高线间隔。[7]

如需查看使用 maplibre-contour 和 raster-dem 瓦片的等高线示例,请参阅添加等高线。

高程分层设色

与山体阴影不同,高程分层设色会根据高程值范围分配颜色,因此非常适合在复杂的景观可视化中细腻地呈现高程变化,或用于需要一眼就能看清高程差异的应用。[14]、[15]

MapLibre 的 color-relief 图层类型会在客户端对地形瓦片执行此操作(数据源为 raster-dem)。[9]、[16]

{
  "id": "color-relief",
  "type": "color-relief",
  "source": "terrain",
  "paint": {
    "color-relief-color": [
      "interpolate",
      ["elevation"],
      0,
      "#00429d",
      1000,
      "#73c1c6",
      2000,
      "#f4777f",
      3000,
      "#93003a"
    ]
  }
}

如需查看基于 DEM 的分层设色完整演示,请参阅添加分层设色图层。

3D 地形

3D 地形会根据高程数据使地图表面起伏。它需要一个 raster-dem 数据源,并通过 map.setTerrain() 启用。[2]、[3]

map.on('load', () => {
  map.addSource('terrain', {
    type: 'raster-dem',
    url: 'pmtiles://terrain.pmtiles',
    tileSize: 512,
    encoding: 'terrarium'
  });

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

3D 地形最适合用于交互式场景,用户可以倾斜和旋转地图,以了解相对高度,或查看覆盖在真实地形上的叠加内容(建筑物、路线、危险区域)。[2]

如需查看完整可用的 3D 地形示例,请参阅3D 地形。

相机倾斜角

只有相机倾斜时,才能看到 3D 地形。可在初始化地图时设置 pitch,也可通过编程方式设置。[2]

const map = new maplibregl.Map({
  container: 'map',
  style: myStyle,
  center: [lng, lat],
  zoom: 12,
  pitch: 60,
  bearing: -30
});
天空图层

启用 3D 地形并倾斜相机后,地平线会变得可见。在地形上方添加天空图层即可填充地平线。[2]、[3]

{
  "id": "sky",
  "type": "sky",
  "paint": {
    "sky-type": "atmosphere",
    "sky-atmosphere-sun": [0, 90],
    "sky-atmosphere-sun-intensity": 15
  }
}

如需查看结合了天空和雾效的地形示例,请参阅天空、雾效与地形。

raster-dem 源的性能说明

在低端设备上,或在高倾角/高缩放级别下,启用晕渲和 3D 地形所需的额外操作(解码 raster-dem 瓦片、构建地形网格,以及绘制覆盖在网格上的图层)可能导致在较低缩放级别加载额外瓦片,并造成屏幕各处的可见细节差异。[13],[26]

性能取决于设备、缩放级别/倾角、瓦片大小和样式复杂度。一般来说,应将地形视为一个小型、专注的图层堆栈(DEM 源加少量可视化图层);如果需要更丰富的视觉效果,又不想增加客户端开销,则应将复杂的制图工作流(多遍复杂晕渲、来自 GIS 或 Blender 的艺术化混合效果)转为预计算栅格。[22],[24]

优化地形性能时还需考虑以下事项:

  • 限制每个 raster-dem 源所依赖的图层数量。 晕渲、色彩地形和 3D 地形都读取相同的高程瓦片。[1],[9] 每增加一个覆盖在地形上的图层(晕渲、raster、fill、line),都会增加总渲染成本,因此应尽量精简地形图层堆栈:只保留少量背景图层(例如一个晕渲或色彩地形图层加影像)以及必要的数据叠加层。[12]

  • 优先使用 hillshade-method,而不是叠加多个晕渲图层。 如果需要更柔和的多方向阴影,应先使用 hillshade-method 选项(例如 "multidirectional"),而不是叠加多个光照方向不同的 hillshade 图层。[18],[25] 多个使用相同 raster-dem 源的晕渲图层会增加绘制通道和 GPU 工作量。

  • 除非确有需要,否则不要重复配置 raster-dem 源。 3D Terrain 示例出于渲染质量方面的考虑,使用了单独的 terrainSource 和 hillshadeSource,但两者指向相同的瓦片。[12] 大多数情况下,地形相关图层(地形、晕渲、色彩地形)应共用一个 raster-dem 源,以避免额外的源配置和潜在的瓦片串扰。[3],[19]

  • 启用 3D 地形时尤其要谨慎。 3D 地形会加载额外的 DEM 瓦片并渲染网格,可能造成明显延迟,尤其是在较高缩放级别和较大倾角下。[2],[26] 应采用保守的夸大系数,避免在低端设备上使用极端倾角,并尽量减少覆盖在地形上的图层数量。

地形金字塔中的瓦片大小与缩放级别

由于金字塔中每个瓦片的字节数会发生变化,任何假设所有缩放级别下每个瓦片的 KB 数都恒定的归档大小估算都会产生偏差,应谨慎看待。与栅格瓦片不同,地形瓦片在不同缩放级别下的大小并非固定。瓦片大小会随缩放级别和地形复杂度变化:极低缩放级别的瓦片可能经过概化或更激进的压缩;极高缩放级别的瓦片覆盖范围较小,地形通常较为均一;而覆盖主要山脉的中等缩放级别瓦片往往包含最详细的地形起伏,因此通常也最大。[23]

生成自己的 DEM 瓦片

要根据源高程数据创建自定义 DEM 瓦片集,请遵循 Tilezen/Mapzen 和社区地形教程中使用的标准 DEM 处理工作流。[5],[8] 请注意,MapLibre 不提供 DEM 瓦片生成工具;它只使用 raster-dem 瓦片。

相关技能

参考资料

  1. MapLibre 样式规范:raster-dem 数据源 — encoding 属性、tileSize — https://maplibre.org/maplibre-style-spec/sources/#raster-dem
  2. MapLibre 3D 地形示例 — https://maplibre.org/maplibre-gl-js/docs/examples/3d-terrain/
  3. RasterDEMTileSource API(MapLibre GL JS) — https://maplibre.org/maplibre-gl-js/docs/API/classes/RasterDEMTileSource/
  4. AWS Terrain Tiles(开放数据) — https://registry.opendata.aws/terrain-tiles/
  5. Tilezen/joerd 编码格式(Terrarium) — https://github.com/tilezen/joerd/blob/master/docs/formats.md
  6. Mapbox Terrain‑RGB v1 瓦片集 — https://docs.mapbox.com/data/tilesets/reference/mapbox-terrain-rgb-v1/
  7. maplibre-contour — 运行时等高线生成 — https://github.com/onthegomap/maplibre-contour
  8. Mapterhorn 地形 PMTiles(Protomaps) — https://protomaps.com/blog/mapterhorn-terrain/
  9. MapLibre 样式规范:图层(hillshade、color-relief) — https://maplibre.org/maplibre-style-spec/layers/
  10. John Nelson 山体阴影技术 — https://adventuresinmapping.com/2014/10/31/a-world-of-hillshading/
  11. 使用 gdaldem 创建色彩地形图和坡度阴影(MasterMaps) — https://blog.mastermaps.com/2012/06/creating-color-relief-and-slope-shading.html
  12. PMTiles 云存储注意事项 — https://docs.protomaps.com/pmtiles/cloud-storage
  13. 使用色彩地形图设置地形样式(MapTiler 指南) — https://docs.maptiler.com/guides/map-design/terrain/color-relief/
  14. OpenTopography 栅格可视化工具 — https://opentopography.org/blog/new-raster-visualization-tools-opentopography
  15. 地形制图概述 — https://en.wikipedia.org/wiki/Terrain_cartography
  16. 添加色彩地形图图层(MapLibre 示例) — https://www.maplibre.org/maplibre-gl-js/docs/examples/add-a-color-relief-layer/
  17. 构建地形图层(GEOG 486,Penn State) — https://courses.ems.psu.edu/geog486/node/868
  18. 其他山体阴影选项(MapLibre GL JS Issue #5665) — hillshade-method(combined、multidirectional、igor)的来源;通过 PR #5768 关闭 — https://github.com/maplibre/maplibre-gl-js/issues/5665
  19. 3D 地形中的山体阴影行为(MapLibre GL JS Discussion #4131) — 记录了实际的质量权衡:在 3D 地形下,山体阴影重新照明不会旋转(纹理缓存所致),分辨率也可能降低 — https://github.com/maplibre/maplibre-gl-js/discussions/4131
  20. 栅格地形分析(QGIS 文档) — 从 DEM 派生坡度、坡向和曲率 — https://docs.qgis.org/latest/en/docs/user_manual/processing_algs/qgis/rasterterrainanalysis.html
  21. gdal_raster_hillshade(GDAL 文档) — https://gdal.org/en/stable/programs/gdal_raster_hillshade.html
  22. 栅格瓦片与矢量瓦片(MapTiler 指南) — https://docs.maptiler.com/guides/how-maps-work/raster-vector-tiles/
  23. 托管 Terrain-RGB 瓦片(MapTiler 指南) — https://docs.maptiler.com/guides/map-tiling-hosting/data-hosting/rgb-terrain-by-maptiler/
  24. 在 Blender 中制作晕渲地形图(TerraLab GIS) — https://www.terralabgis.com/blog/blender-hillshade
  25. 添加多方向山体阴影图层(MapLibre GL JS 示例) — https://www.maplibre.org/maplibre-gl-js/docs/examples/add-a-multidirectional-hillshade-layer/
  26. 启用地形后高缩放级别下 FPS 严重下降(MapLibre GL JS Issue #7699) — 截至撰写时仍未解决;根因已确定为近距离缩放时 getDEMElevation 与 placement/collision 的开销 — https://github.com/maplibre/maplibre-gl-js/issues/7699

延伸阅读(当前未在此技能中引用,供审阅)


此技能内容为快照。 如果主要来源与此内容相矛盾——包括上述参考资料、MapLibre 当前文档,或运行 MapLibre 时的实际表现——请以该来源为准。遵循该来源,然后报告此处的分歧,并注明来源和 MapLibre 版本:编辑你安装的副本对其他人毫无帮助,而且下一次更新时会被覆盖。

评论

支持 Markdown