Skip to content

地形和3D要素

本页记录 Mapbox GL JS 中的 地形和3D要素,重点关注地形高程、3D 建筑物(fill extrusions)和光照如何协同工作。有关核心渲染系统的信息,请参阅 渲染系统图层渲染

概述

Mapbox GL JS 支持渲染 3D terrain 和 extruded features(如建筑物),以及光照和阴影以创建逼真的 3D 地图。Terrain 系统使用数字高程模型(DEM)创建 3D 表面,而 fill extrusion 系统将 2D polygons 转换为具有高度的 3D shapes。

Terrain 系统

Terrain 系统使用 raster DEM(数字高程模型)sources 渲染 3D terrain。当启用 terrain 时,所有地图元素(包括 markers、layers 和 3D objects)都相对于 terrain 表面定位。

Terrain 配置

Terrain 在 map style 的 terrain 属性中配置:

{
  "terrain": {
    "source": "mapbox-dem",
    "exaggeration": 1.5
  }
}
PropertyTypeDescriptionDefault
sourcestringraster-dem source 的 ID(required)
exaggerationnumberTerrain elevation 的缩放因子1

Terrain 也可以通过编程方式启用或更新:

map.setTerrain({ source: "mapbox-dem", exaggeration: 1.5 });

要禁用 terrain:

map.setTerrain(null);

Terrain 数据源

Terrain 需要一个提供 elevation 数据的 raster-dem source。此 source 类型专为数字高程模型设计:

{
  "sources": {
    "mapbox-dem": {
      "type": "raster-dem",
      "url": "mapbox://mapbox.mapbox-terrain-dem-v1",
      "tileSize": 512,
      "maxzoom": 14
    }
  }
}

Terrain 处理管线

下图展示了 terrain elevation 数据如何流经系统:

SVG
100%

Terrain 实现细节

Terrain 系统在 shader 代码中包含几个关键函数:

  1. Elevation 采样: terrain vertex shader 中的 elevation() 函数采样 DEM 数据以确定任何给定点的高度。

  2. Terrain-Layer 集成: 所有渲染 layers 使用 shader 函数查询 terrain elevation 并相应调整其 geometry。

  3. 法线计算: 为 terrain 上的光照计算计算表面法线。

当 terrain 处于活动状态时,所有地图 features(包括建筑物、道路和 labels)都根据底层的 terrain elevation 定位。这就是为什么你会在各种 layer shaders(包括 fill extrusions)中看到对 terrain elevation 函数的引用的原因。

Terrain shader 包含处理平坦和插值 elevation 的函数、建筑物足迹的特殊处理以及 terrain tiles 之间的正确混合。

Fill Extrusions

Fill extrusions 将 2D polygons 转换为具有高度的 3D shapes,通常用于渲染建筑物。它们支持高级视觉特性,如圆角边缘、光照、阴影和 patterns。

Fill Extrusion 配置

Fill extrusions 在 style 中配置为一种 layer 类型:

{
  "id": "buildings",
  "type": "fill-extrusion",
  "source": "composite",
  "source-layer": "building",
  "paint": {
    "fill-extrusion-color": "#aaa",
    "fill-extrusion-height": ["get", "height"],
    "fill-extrusion-base": ["get", "min_height"],
    "fill-extrusion-opacity": 0.8,
    "fill-extrusion-edge-radius": 0.5
  }
}

Fill Extrusion 属性

PropertyDescriptionDefault
fill-extrusion-heightExtrusion 的高度0
fill-extrusion-baseExtrusion 的基准高度0
fill-extrusion-colorExtrusion 的颜色"#000000"
fill-extrusion-opacityExtrusion 的不透明度1
fill-extrusion-pattern用作 pattern 的图像undefined
fill-extrusion-vertical-gradient是否应用垂直渐变true
fill-extrusion-ambient-occlusion-intensity控制环境光遮蔽效果0.3
fill-extrusion-ambient-occlusion-radius环境光遮蔽的半径3.0
fill-extrusion-edge-radius圆角边缘的半径0
fill-extrusion-rounded-roof是否圆化屋顶边缘true

Fill Extrusion 处理管线

此图展示了 fill extrusions 如何被处理和渲染:

SVG
100%

Fill Extrusion 和 Terrain

当启用 terrain 时,fill extrusions 会调整到底层的 terrain elevation。这包括:

  1. 基准 Elevation: Extrusion 的基准位置在 terrain elevation 加上基准高度处
  2. 高度: Extrusion 从基准延伸到 terrain 上方的指定高度
  3. 法线: 调整表面法线以便在倾斜 terrain 上进行正确光照

Shader 代码具有特殊处理,确保建筑物即使在斜坡上也正确锚定到 terrain。Fill extrusions 通过 shader 中的 elevation() 函数查询 terrain elevation。

光照系统

光照系统为 terrain 和 3D features(如 fill extrusions)提供逼真的照明。它支持具有可定制属性的环境光和定向光。

光照配置

Lights 在 map style 的 lights 数组中配置:

{
  "lights": [
    {
      "id": "ambient",
      "type": "ambient",
      "properties": {
        "color": "hsl(0, 0%, 100%)",
        "intensity": 0.5
      }
    },
    {
      "id": "directional",
      "type": "directional",
      "properties": {
        "color": "hsl(0, 0%, 100%)",
        "intensity": 0.5,
        "direction": [180, 30],
        "cast-shadows": true,
        "shadow-intensity": 0.8
      }
    }
  ]
}

Lights 也可以通过编程方式设置:

map.setLights([
  {
    type: "ambient",
    id: "ambient_light",
    properties: {
      color: "white",
      intensity: 0.5
    }
  },
  {
    type: "directional",
    id: "directional_light",
    properties: {
      color: "white",
      intensity: 0.7,
      direction: [180, 45],
      "cast-shadows": true,
      "shadow-intensity": 1.0
    }
  }
]);

光照类型和属性

TypePropertyDescriptionDefault
ambientcolorLight color"white"
ambientintensityLight intensity (0-1)0.5
directionalcolorLight color"white"
directionalintensityLight intensity (0-1)0.5
directionaldirection[azimuth, polar] 以度为单位[180, 30]
directionalcast-shadows是否投射阴影false
directionalshadow-intensity阴影暗度 (0-1)0.8

光照和阴影系统

SVG
100%

光照和阴影实现

光照系统在 shader 代码中实现,将光照和阴影计算应用于 3D features。关键组件包括:

  1. 环境光照: 提供无方向性的全局照明
  2. 定向光照: 模拟具有方向和阴影的阳光
  3. 基于法线的光照: 使用表面法线计算光照强度(NdotL)
  4. 阴影映射: 从光源视角渲染深度图以计算阴影
  5. 阴影偏置: 通过智能偏置计算防止阴影 acne
  6. 级联阴影映射: 为不同距离范围使用多个阴影映射

光照 shader 包括专门的函数:

  • apply_lighting(): 对表面应用环境光和定向光
  • calculate_NdotL(): 计算法线和光照方向的点积
  • shadow_occlusion(): 确定片段有多少在阴影中

高级 Fill Extrusion 特性

Fill extrusions 支持几种高级视觉特性,以增强真实感:

环境光遮蔽

环境光遮蔽模拟在光线被遮挡的角落和缝隙中发生的微妙变暗。Fill extrusions 通过 fill-extrusion-ambient-occlusion-* 属性支持此功能:

"fill-extrusion-ambient-occlusion-intensity": 0.3,
"fill-extrusion-ambient-occlusion-radius": 3.0

泛光

泛光模拟建筑物底部的光源,适用于夜间场景:

"fill-extrusion-flood-light-color": "rgb(255, 255, 146)",
"fill-extrusion-flood-light-intensity": 0.2,
"fill-extrusion-flood-light-ground-attenuation": 0.7,
"fill-extrusion-flood-light-ground-radius": 5.0

圆角边缘

Fill extrusions 支持圆角边缘和角落,以创建更逼真的建筑物:

"fill-extrusion-edge-radius": 0.5,
"fill-extrusion-rounded-roof": true

Patterns 和纹理

Fill extrusions 可以使用图像 patterns 进行纹理化:

"fill-extrusion-pattern": "building_pattern"

代码结构

SVG
100%

性能考虑

使用 terrain 和 3D features 时,请考虑这些性能提示:

  1. Terrain 复杂度: 更高的 terrain exaggeration 值需要更多的 geometry 处理
  2. Fill Extrusion 密度: 大量的 3D 建筑物可能会影响性能
  3. 阴影: Shadow maps 需要额外的渲染 passes,可能会很昂贵
  4. 边缘半径: Fill extrusions 上的圆角边缘需要更多的 geometry 处理
  5. 环境光遮蔽: 更高的环境光遮蔽值需要更多的采样

调试和开发工具

Mapbox GL JS 包含几个用于 terrain 和 3D features 的调试工具:

  1. 3D Playground: 用于测试 3D features 的综合调试页面(debug/3d-playground.html
  2. Terrain Debug: 专门用于 terrain 的调试页面(debug/terrain-debug.html
  3. Terrain Elevation Debug Widget: 显示光标位置处 terrain elevation 的小部件

这些工具允许你实时调整参数,如光照、阴影质量、terrain exaggeration 和建筑物外观。

完整示例

这是一个包含 terrain、3D 建筑物和光照的完整 style 示例:

{
  "version": 8,
  "sources": {
    "mapbox-dem": {
      "type": "raster-dem",
      "url": "mapbox://mapbox.mapbox-terrain-dem-v1",
      "tileSize": 512,
      "maxzoom": 14
    },
    "mapbox-streets": {
      "type": "vector",
      "url": "mapbox://mapbox.mapbox-streets-v8"
    }
  },
  "terrain": {
    "source": "mapbox-dem",
    "exaggeration": 1.5
  },
  "lights": [
    {
      "id": "ambient",
      "type": "ambient",
      "properties": {
        "color": "hsl(0, 0%, 100%)",
        "intensity": 0.5
      }
    },
    {
      "id": "directional",
      "type": "directional",
      "properties": {
        "color": "hsl(30, 80%, 95%)",
        "intensity": 0.7,
        "direction": [210, 40],
        "cast-shadows": true,
        "shadow-intensity": 0.8
      }
    }
  ],
  "layers": [
    // 基础 layers 为简洁起见省略
    {
      "id": "buildings",
      "type": "fill-extrusion",
      "source": "mapbox-streets",
      "source-layer": "building",
      "paint": {
        "fill-extrusion-color": "hsl(35, 8%, 85%)",
        "fill-extrusion-height": ["get", "height"],
        "fill-extrusion-base": ["get", "min_height"],
        "fill-extrusion-opacity": 0.9,
        "fill-extrusion-edge-radius": 0.5,
        "fill-extrusion-rounded-roof": true,
        "fill-extrusion-ambient-occlusion-intensity": 0.3,
        "fill-extrusion-ambient-occlusion-radius": 3.0
      }
    }
  ]
}