地形和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
}
}| Property | Type | Description | Default |
|---|---|---|---|
| source | string | raster-dem source 的 ID | (required) |
| exaggeration | number | Terrain 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 数据如何流经系统:
Terrain 实现细节
Terrain 系统在 shader 代码中包含几个关键函数:
Elevation 采样: terrain vertex shader 中的
elevation()函数采样 DEM 数据以确定任何给定点的高度。Terrain-Layer 集成: 所有渲染 layers 使用 shader 函数查询 terrain elevation 并相应调整其 geometry。
法线计算: 为 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 属性
| Property | Description | Default |
|---|---|---|
| fill-extrusion-height | Extrusion 的高度 | 0 |
| fill-extrusion-base | Extrusion 的基准高度 | 0 |
| fill-extrusion-color | Extrusion 的颜色 | "#000000" |
| fill-extrusion-opacity | Extrusion 的不透明度 | 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 如何被处理和渲染:
Fill Extrusion 和 Terrain
当启用 terrain 时,fill extrusions 会调整到底层的 terrain elevation。这包括:
- 基准 Elevation: Extrusion 的基准位置在 terrain elevation 加上基准高度处
- 高度: Extrusion 从基准延伸到 terrain 上方的指定高度
- 法线: 调整表面法线以便在倾斜 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
}
}
]);光照类型和属性
| Type | Property | Description | Default |
|---|---|---|---|
| ambient | color | Light color | "white" |
| ambient | intensity | Light intensity (0-1) | 0.5 |
| directional | color | Light color | "white" |
| directional | intensity | Light intensity (0-1) | 0.5 |
| directional | direction | [azimuth, polar] 以度为单位 | [180, 30] |
| directional | cast-shadows | 是否投射阴影 | false |
| directional | shadow-intensity | 阴影暗度 (0-1) | 0.8 |
光照和阴影系统
光照和阴影实现
光照系统在 shader 代码中实现,将光照和阴影计算应用于 3D features。关键组件包括:
- 环境光照: 提供无方向性的全局照明
- 定向光照: 模拟具有方向和阴影的阳光
- 基于法线的光照: 使用表面法线计算光照强度(NdotL)
- 阴影映射: 从光源视角渲染深度图以计算阴影
- 阴影偏置: 通过智能偏置计算防止阴影 acne
- 级联阴影映射: 为不同距离范围使用多个阴影映射
光照 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": truePatterns 和纹理
Fill extrusions 可以使用图像 patterns 进行纹理化:
"fill-extrusion-pattern": "building_pattern"代码结构
性能考虑
使用 terrain 和 3D features 时,请考虑这些性能提示:
- Terrain 复杂度: 更高的 terrain exaggeration 值需要更多的 geometry 处理
- Fill Extrusion 密度: 大量的 3D 建筑物可能会影响性能
- 阴影: Shadow maps 需要额外的渲染 passes,可能会很昂贵
- 边缘半径: Fill extrusions 上的圆角边缘需要更多的 geometry 处理
- 环境光遮蔽: 更高的环境光遮蔽值需要更多的采样
调试和开发工具
Mapbox GL JS 包含几个用于 terrain 和 3D features 的调试工具:
- 3D Playground: 用于测试 3D features 的综合调试页面(
debug/3d-playground.html) - Terrain Debug: 专门用于 terrain 的调试页面(
debug/terrain-debug.html) - 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
}
}
]
}