图层渲染
本文档描述 Mapbox GL JS 如何使用 WebGL 将不同的图层类型渲染到屏幕上。它涵盖了渲染管线、shader 程序以及用于各种 图层类型(包括 lines、fills 和 3D extrusions)的技术。关于整体渲染架构的信息,请参阅 核心架构。关于协调渲染的绘图器的详细信息,请参阅 绘图器。
渲染管线概览
图层渲染过程通过一系列步骤将样式定义的图层转换为屏幕上的视觉元素:
管线包含以下关键步骤:
- Style 处理: 将 style specification 转换为具有评估属性的 layer 对象
- Geometry 处理: 将 geometry 组织为 "buckets" 以实现高效渲染
- Program 选择: 根据 layer 类型和属性选择适当的 shader 程序
- Buffer 设置: 准备用于渲染的顶点和索引 buffer
- Uniform 值: 根据 layer 属性设置 uniform 值
- Draw Call: 发出 WebGL draw 命令以渲染 layer
Layer 类型及其渲染
Line Layer 渲染
Line layers(如道路、河流和边界)使用专门优化的 shader 程序和 buffer 布局进行渲染。
Line Geometry 表示
Line features 被处理为包含以下内容的 buffer:
- 顶点位置
- Line normals(用于宽度)
- 高级样式的属性(dasharray、gradients 等)
LineBucket 类处理 line geometry 的处理:
Line 样式属性
Lines 可以使用各种属性进行样式设置:
line-width: 控制 line 粗细line-color: 定义 line 颜色line-opacity: 控制透明度line-dasharray: 创建虚线 patternline-gradient: 沿 lines 应用颜色渐变line-pattern: 应用图像 pattern
Line Shader 程序
Line 渲染根据样式使用不同的 shader 程序:
Vertex shader 定位 line geometry 并计算以下属性:
- 用于宽度的 line normals
- 用于 patterns/gradients 的纹理坐标
- Terrain elevation 调整
Fragment shader 处理:
- 颜色应用(纯色、渐变或 pattern)
- Dash patterns
- Alpha blending
- 抗锯齿
Fill Layer 渲染
Fill layers 渲染 polygon features,如陆地、水体和建筑足迹。
Fill Shader 程序
Fill 渲染使用多个 shader 程序:
- Standard Fill: 用于纯色填充
- Fill Pattern: 用于带有图像 pattern 的填充
- Fill Outline: 用于带有轮廓线的填充
- Fill Outline Pattern: 用于带有 pattern 的轮廓填充
Fill Extrusion Layer 渲染
Fill extrusion layers 通过 extruding 2D polygons 来渲染 3D features,如建筑物。
Fill extrusion 渲染的关键特性:
- 高度 extrusion: 通过向上 extruding 将 2D polygons 转换为 3D
- 光照模型: 定向和环境光照
- 环境光遮蔽: 在角落和缝隙中创建真实的阴影
- 边缘半径: 圆形建筑边缘
- 泛光: 地面级别的光照效果
- 阴影映射: 在地面上投射阴影
Shader 程序配置
渲染系统根据 layer 属性动态配置 shader 程序:
用于条件编译的 Shader Defines
Shader 程序使用预处理指令根据 layer 属性启用/禁用功能:
RENDER_LINE_DASH: 启用 lines 的 dash pattern 渲染RENDER_LINE_GRADIENT: 启用 lines 的渐变渲染RENDER_LINE_PATTERN: 启用 lines 的 pattern 渲染ELEVATED: 启用 terrain elevation 集成LIGHTING_3D_MODE: 启用高级 3D 光照
Uniform 值
Uniform 值根据 layer 属性计算并在渲染前设置:
// Line uniform 值示例(简化)
const uniformValues = {
'u_matrix': calculateMatrix(painter, tile, layer, matrix),
'u_pixels_to_tile_units': pixelsToTileUnits,
'u_device_pixel_ratio': pixelRatio,
'u_width_scale': widthScale,
'u_dash_image': 0,
'u_gradient_image': 1,
'u_emissive_strength': layer.paint.get('line-emissive-strength')
};高级渲染技术
Terrain 集成
Layers 可以与 terrain elevation 集成:
代码使用特殊的 shader 逻辑来处理 elevation:
// Line vertex shader 中的示例
#ifdef ELEVATED
float ele0 = sample_elevation(offset_pos);
float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
float ele_max = max(ele0, 0.5 * (ele1 + ele2));
ele = ele_max - ele0 + ele1 + a_z_offset;光照和阴影
Mapbox GL JS 包含一个复杂的 3D elements 光照系统:
- 定向光照: 模拟具有可配置方向和强度的阳光
- 环境光照: 为所有表面提供基础照明
- 阴影映射: 从建筑物和 terrain 创建真实阴影
- 泛光: 建筑物的地面级别照明
阴影映射使用 shadow maps 和深度比较实现:
// Fragment shader 中的阴影映射
float shadow_occlusion(highp vec4 light_view_pos0, highp vec4 light_view_pos1, float view_depth, highp float bias) {
// 采样 shadow maps 并确定点是否在阴影中
// ...
return 1.0 - (u_shadow_intensity * occlusion);
}性能考虑
渲染系统采用几种优化策略:
- Shader 程序重用: 类似的 layers 共享编译的 shader 程序
- Buffer 管理: Geometry 存储在优化的 buffer 布局中
- 实例化: 尽可能使用实例化渲染来处理相似的 features
- 动态 defines: 仅通过 defines 启用必要的 shader 功能
- Z-fighting 防止: 仔细管理深度值以防止视觉伪影
特定 Layer 类型的渲染
以下是不同 layer 类型如何利用渲染管线的综合视图:
Layer-Terrain 交互
当启用 terrain 时,layers 需要特殊处理以与 elevation 数据正确集成:
| Layer Type | Terrain 处理方法 | 关键属性 |
|---|---|---|
| Line | 沿 line 采样 elevation | line-elevation-reference, line-z-offset |
| Fill | 覆盖在 terrain 上 | fill-extrusion-height, fill-extrusion-base |
| Fill-Extrusion | 从 terrain 扩展 | 基于 terrain elevation 的高度调整 |
| Symbol | 放置在 terrain 表面上 | 基于 elevation 的位置调整 |
Layers 和 terrain 之间的交互通过采样 elevation 数据并相应调整顶点位置的 shader 代码进行管理。
总之,Mapbox GL JS 中的 layer 渲染系统是一个复杂的管线,它使用 WebGL 将样式定义转换为视觉元素。该系统采用各种优化技术和针对每种 layer 类型定制的渲染方法,以实现性能和视觉质量。