GIS
影像图层
前情回顾:03 四叉树与 LOD 讲清了瓦片怎么调度(编号、四叉树、剔除、LOD)。本篇打开瓦片的内容黑盒——瓦片里装的是什么数据?不同地图服务的协议差在哪?多图层怎么在 GPU 上叠加?
直觉问题
打开任何一个 Web 地图应用,看到的”地图”往往不是一张图,而是好几层叠出来的:
- 底层:卫星图(XYZ 协议,每张瓦片是预切片的 PNG)
- 中层:道路和地名标注(WMS 协议,按需出图)
- 顶层:自己画的矢量标记(WFS 或 MVT,客户端渲染)
这背后立刻冒出三个问题:
- OSM、天地图、Google、WMS 服务,URL 长得完全不一样——
https://tile.openstreetmap.org/{z}/{x}/{y}.pngvshttps://server/wms?LAYERS=roads&BBOX=...,它们背后是什么不同的协议?为什么不能统一? - 同一块地图区域,卫星图、道路、标注三层是怎么”叠”在一起的?是简单的 z-order 还是有什么数学混合?
- Mapbox/MapLibre 的”矢量瓦片”是什么?为什么和 OSM 的”栅格瓦片”不一样?
读完本篇,你能回答:“WMS 和 WMTS 差在哪?”、“栅格图层和矢量图层数据模型有何本质不同?”、“Multiply 混合模式与 Screen 混合模式公式差在哪?“
核心概念白话讲
用”网页图片”理解 XYZ 协议
XYZ 协议是最朴素的瓦片服务——每个瓦片就是一张 PNG/JPG/WebP 图片,URL 唯一决定是哪张:
https://tile.openstreetmap.org/10/842/388.png
│ │ └─ y(行号)
│ └───── x(列号)
└──────── z(缩放级别)
打开浏览器直接访问这个 URL,你就拿到一张 256×256 的 PNG。整个 OSM 全球瓦片就是约 张这样的图片,预切片存在 CDN 上。客户端只要”知道 URL”就能拿。
用”打印报表”理解 WMS 协议
WMS(Web Map Service)反其道而行——它不预切片,每次请求都由服务器实时出图:
https://server/wms?
SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap
&LAYERS=roads,rivers
&BBOX=-74.05,40.70,-74.00,40.75
&WIDTH=512&HEIGHT=512
&FORMAT=image/png
服务器拿到这些参数(图层 + 地理范围 + 输出尺寸),渲染出一张 512×512 的 PNG 返回。同一个 BBOX 可以请求不同 LAYERS,灵活但慢——每次都要服务端渲染。
用”透明幻灯片”理解图层叠放
把多个图层想象成一叠透明幻灯片:
┌─────────────────────────┐
│ 标注层(点/线/文字) │ ← 最上层
├─────────────────────────┤
│ 道路层(矢量线) │
├─────────────────────────┤
│ 行政边界(淡色面) │
├─────────────────────────┤
│ 卫星底图(不透明) │ ← 最下层
└─────────────────────────┘
每层独立绘制,从下往上渲染。底层通常不透明(卫星图),上层通常带透明度(道路、标注)。
NOTE
关键认知:图层叠放不只是 z-order——还有**混合模式(blend mode)**决定像素如何合成。Normal 模式是 alpha 加权平均,Multiply/Screen/Overlay 等模式有完全不同的视觉效果。
用”调色板混合”理解多纹理混合
GPU 渲染瓦片时,每个瓦片可能有多个纹理(底图 + 道路 + 标注),需要在 fragment shader 里实时合成。这就是多纹理混合(multi-texture blending):
// GLSL 伪代码
vec4 base = texture2D(uBaseTex, vUV); // 卫星底图
vec4 road = texture2D(uRoadTex, vUV); // 道路
vec4 label = texture2D(uLabelTex, vUV); // 标注
// 顺序混合
vec4 color = mix(base, road, road.a); // Normal: alpha 加权
color = mix(color, label, label.a);
gl_FragColor = color;
mix(x, y, a) 是 GLSL 内置函数,等价于 x*(1-a) + y*a。多个图层就是嵌套 mix。
原理与数学/机制
1. 六大切片协议
Web GIS 的图层服务有 6 大主流协议,分两大类:
1.1 栅格协议(返回图片)
| 协议 | 全称 | 切片时机 | URL 形式 | 标准来源 |
|---|---|---|---|---|
| XYZ | Slippy Map | 预切片 | /{z}/{x}/{y}.png | OSM Wiki |
| TMS | Tile Map Service | 预切片 | /{z}/{x}/{y}.png(y 反向) | OSGeo |
| WMS | Web Map Service | 动态出图 | ?REQUEST=GetMap&BBOX=... | OGC |
| WMTS | Web Map Tile Service | 预切片 | ?REQUEST=GetTile 或 REST | OGC |
1.2 矢量协议(返回几何)
| 协议 | 全称 | 数据形态 | 切片时机 | 标准来源 |
|---|---|---|---|---|
| WFS | Web Feature Service | GeoJSON / GML | 动态查询 | OGC |
| MVT | Mapbox Vector Tiles | 二进制 PBF | 预切片 | Mapbox Spec |
1.3 协议详解
XYZ vs TMS:见 Phase 3,y 轴方向相反。
WMS(动态出图):
- 服务器每次请求都实时渲染,性能远不如预切片
- 优势:灵活——同一 BBOX 可以请求不同图层、不同样式、不同 CRS
- 适用:低频访问、样式经常变化的服务(如某政府专题图)
WMTS(WMS 的预切片版):
- 把 WMS 的”动态出图”换成”预切片 + 缓存”
- 接口形式:REST 风格
/{Layer}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png或 KVP(键值对 URL) - OGC 标准下 WMTS 默认用 EPSG:4326(geodetic)瓦片方案,但也可配置 EPSG:3857
- 适用:大规模、高并发地图服务(政府门户、企业底图)
WFS(矢量数据查询):
- 返回的不是图片,是 GeoJSON / GML 格式的矢量数据
- 客户端拿到几何后自己渲染(点画成什么颜色、线画多粗都客户端决定)
- 支持空间过滤(
BBOX)和属性过滤(CQL_FILTER) - 适用:矢量对象交互(点击高亮、属性查询、客户端样式)
MVT(Mapbox Vector Tiles):
- 矢量数据按 z/x/y 预切片成二进制 PBF 文件
- 介于 XYZ(栅格预切片)和 WFS(矢量动态)之间——既保留矢量的”客户端渲染”灵活性,又有预切片的”高并发”性能
- Mapbox / MapLibre / deck.gl 主战场
- 适用:现代 Web 地图(Mapbox Studio 自定义样式、海量数据流畅缩放)
IMPORTANT
协议选型决策树:
- 要快且数据不变 → 栅格预切片(XYZ / TMS / WMTS)
- 要灵活且低频访问 → WMS 动态出图
- 要矢量交互(点击、样式)→ MVT 预切片矢量(现代)或 WFS 动态矢量(传统)
2. OGC 标准体系
**OGC(Open Geospatial Consortium)**是国际地理信息标准组织,制定了一族 Web 服务标准:
OGC 标准
│
┌───────┼────────┐
服务 数据 编码
│ │ │
┌────┼───┐ ├─GML ├─WKT
WMS WMTS WFS ├─GeoJSON └─WKB
│
CityGML
3D Tiles(Phase 9)
- 服务标准:WMS / WMTS / WFS / WCS(栅格数据)/ WPS(处理服务)
- 编码标准:GML(XML 矢量)/ GeoJSON / CityGML(三维城市)/ 3D Tiles(三维瓦片)
- 角色:OGC 标准让不同厂商的 GIS 软件(ESRI / QGIS / 开源引擎)能互操作——同一份 WMS 服务可以被 QGIS、ArcGIS、OpenLayers 同时消费
3. 栅格图层 vs 矢量图层
两种图层数据模型本质不同:
| 维度 | 栅格图层 | 矢量图层 |
|---|---|---|
| 数据本质 | 像素矩阵(每个像素有 RGB 值) | 几何对象(点 / 线 / 面 + 属性) |
| 缩放表现 | 放大后模糊(像素被拉伸) | 无限放大保持锐利 |
| 文件大小 | 大(每瓦片 256×256×3 = 192 KB) | 小(PBF 编码紧凑) |
| 渲染成本 | 低(GPU 直接纹理贴图) | 高(客户端绘制几何) |
| 样式灵活性 | 低(样式在服务端固化) | 高(客户端自由定义) |
| 交互能力 | 弱(只能识别瓦片级别) | 强(每个要素可独立交互) |
| 典型协议 | XYZ / TMS / WMS / WMTS | WFS / MVT |
| 典型场景 | 卫星图、地形渲染图 | 道路、行政边界、自定义标记 |
4. 纹理混合数学
4.1 Normal + alpha blending(最常用)
两个图层叠加,Normal 模式 + alpha 通道:
其中 是 RGB 颜色向量, 是 overlay 图层的不透明度(0-1)。
GLSL:mix(base, overlay, overlay.a)
4.2 Multiply(正片叠底)
每个通道相乘(颜色归一化到 ):
效果:颜色变暗——白色(1.0)保持底色不变,黑色(0.0)变全黑。常用于阴影叠加、纸质效果。
4.3 Screen(滤色)
Multiply 的反向操作:
效果:颜色变亮——黑色保持底色不变,白色变全白。常用于光晕、发光效果、夜间地图。
4.4 Overlay(叠加)
Multiply 和 Screen 的混合——根据底色亮度分支:
效果:暗处更暗、亮处更亮(增加对比度),中间灰保持。常用于地形阴影增强、对比度提升。
4.5 4 种混合模式对比
| 模式 | 公式 | 效果 | Web GIS 典型用途 |
|---|---|---|---|
| Normal | 加权平均 | 标准透明叠加 | 95% 场景(道路叠加在卫星图上) |
| Multiply | 变暗 | 阴影、纸质效果 | |
| Screen | 变亮 | 光晕、夜间地图 | |
| Overlay | 暗处 Multiply,亮处 Screen | 增加对比度 | 地形阴影增强 |
TIP
生产建议:默认用 Normal + alpha 即可。Multiply / Screen / Overlay 是高级用法,主要用于艺术化地图样式(如夜间模式、复古地图)或地形渲染增强。
4.6 多层嵌套混合
3 个图层(base + layer1 + layer2)按 Normal 模式顺序混合:
GLSL 写法:
vec4 color = mix(base, layer1, layer1.a);
color = mix(color, layer2, layer2.a);
每多一层就多嵌套一次 mix。Web GIS 引擎通常限制图层数量(如最多 8 层),避免 shader 嵌套过深影响性能。
5. HTTP 并发优化
瓦片加载是高并发场景——单次缩放可能触发 50-200 个瓦片请求。HTTP 协议版本对并发性能影响巨大:
| 协议 | 单连接并发数 | 典型场景 | 瓦片加载性能 |
|---|---|---|---|
| HTTP/1.1 | 6(浏览器限制) | 老旧服务器、自托管 | 慢,需 域名分片(domain sharding) |
| HTTP/2 | 数百(多路复用) | 主流 CDN(Cloudflare / CloudFront) | 快,单连接多请求 |
| HTTP/3 | 数百(QUIC) | Google / Cloudflare 边缘 | 更快(无队头阻塞) |
域名分片(HTTP/1.1 时代)
HTTP/1.1 单域名只能并发 6 个请求。瓦片服务通常用多个子域名扩展并发:
https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
https://b.tile.openstreetmap.org/{z}/{x}/{y}.png
https://c.tile.openstreetmap.org/{z}/{x}/{y}.png
3 个子域名 × 6 连接 = 18 个并发。OSM / Google Maps 早期都用这种 trick。
WARNING
HTTP/2 时代不要再域名分片——多路复用让单域名可并发数百请求,反而多域名增加 DNS / TLS 握手开销。OSM 在 HTTP/2 CDN 上已不推荐 a/b/c 子域名。
6. 图层管线流程
关键节点:
- A:用户声明图层(如
addLayer(type='xyz', url='...', opacity=0.8)) - B:根据相机位置算出本帧需要的瓦片 z/x/y,拼接 URL
- C:HTTP/2 单连接并发请求多个瓦片
- D:PNG → ImageBitmap,PBF → 几何数据
- E:把 ImageBitmap 上传到 GPU 作为纹理
- F:fragment shader 内对多个纹理做 mix 混合
- G:最终颜色写到 Framebuffer(参考 Phase 1 渲染循环 的步骤四/五/六)
可视化对比与动手实验
对比表一:6 种切片协议全景
| 协议 | 数据形态 | 切片时机 | URL 形式 | 缓存策略 | 典型使用者 |
|---|---|---|---|---|---|
| XYZ | 栅格 PNG | 预切片 | /{z}/{x}/{y}.png | CDN | OSM / Google Maps / 百度 |
| TMS | 栅格 PNG | 预切片 | /{z}/{x}/{y}.png(y 反向) | CDN | NASA GIBS / 老 OGC |
| WMS | 栅格 PNG | 动态 | ?REQUEST=GetMap&BBOX=... | 无(每次实时) | 政府专题图 |
| WMTS | 栅格 PNG | 预切片 | REST 或 KVP | CDN | 政府门户、企业底图 |
| WFS | 矢量 GeoJSON/GML | 动态查询 | ?REQUEST=GetFeature&BBOX=... | 无 | 传统 GIS 互操作 |
| MVT | 矢量 PBF | 预切片 | /{z}/{x}/{y}.pbf | CDN | Mapbox / MapLibre / deck.gl |
对比表二:栅格 vs 矢量图层数据模型
| 维度 | 栅格图层 | 矢量图层 |
|---|---|---|
| 数据本质 | 像素矩阵 | 几何对象 + 属性 |
| 缩放表现 | 放大模糊 | 无限锐利 |
| 文件大小 | 192 KB/瓦片 | 5-50 KB/瓦片(PBF) |
| 渲染成本 | 低(GPU 贴图) | 高(客户端绘制) |
| 样式灵活性 | 低(服务端固化) | 高(客户端定义) |
| 交互能力 | 弱(瓦片级) | 强(要素级) |
| 典型协议 | XYZ / WMS / WMTS | WFS / MVT |
对比表三:4 种图层混合模式
| 模式 | 数学公式 | 视觉效果 | 典型用途 |
|---|---|---|---|
| Normal | 标准透明叠加 | 95% 场景 | |
| Multiply | 变暗 | 阴影、纸质感 | |
| Screen | 变亮 | 光晕、夜间地图 | |
| Overlay | 暗处 Multiply,亮处 Screen | 增加对比度 | 地形阴影增强 |
动手实验一:观察 OSM Tile URL
打开 OpenStreetMap,缩放到某城市,右键任意瓦片 → 复制图片地址:
- URL 形如
https://tile.openstreetmap.org/15/27176/12421.png - 注意
15是 z(缩放级别),27176是 x,12421是 y - 改 URL 最后一个数字看相邻瓦片
动手实验二:用 QGIS 添加 WMS 服务
如果你装了 QGIS,添加一个公共 WMS:
- Layer → Add Layer → Add WMS Layer
- 添加服务 URL(如 NOAA WMS)
- 选择 Layer,点击 Add
- 在 Network 面板观察请求 URL(注意
BBOX、WIDTH、HEIGHT、FORMAT等参数) - 缩放时观察 WMS 每次都重新请求(动态出图,与 XYZ 的预切片对比明显)
动手实验三:用浏览器 DevTools 观察瓦片并发
打开任意 Web 地图,按 F12 → Network → 过滤 png:
- HTTP/1.1 站点:同时最多 6 个请求,其余排队
- HTTP/2 站点(OSM 现在是 HTTP/2):单连接同时跑 50+ 请求
- 注意
Protocol列(h2 = HTTP/2,http/1.1 = HTTP/1.1)
常见误区
WARNING
误区 1:以为 WMS 也有瓦片缓存。 ✅ 正确:WMS 是动态出图——每次请求都实时渲染。要缓存就用 WMTS(同 OGC 标准的预切片版本)。
WARNING
误区 2:以为 WFS 返回图片。 ✅ 正确:WFS 返回矢量数据(GeoJSON / GML),客户端拿到几何后自己渲染。返回图片的是 WMS / WMTS。
WARNING
误区 3:以为图层叠放就是按 z-order。 ✅ 正确:z-order 决定绘制顺序,blend mode 决定像素如何合成。Normal 是 alpha 加权平均,Multiply / Screen / Overlay 是不同的数学公式。
WARNING
误区 4:以为 HTTP/2 对瓦片加载影响不大。 ✅ 正确:HTTP/1.1 单域名只能并发 6 个请求;HTTP/2 多路复用让单连接并发数百个。瓦片是高并发场景(单次缩放 50-200 个请求),HTTP/2 让加载时间缩短 3-5 倍。
WARNING
误区 5:以为矢量图层也走栅格瓦片协议。 ✅ 正确:矢量图层有专属协议——传统用 WFS(动态查询 GeoJSON),现代用 MVT(预切片 PBF)。两者都返回几何数据,客户端 GPU 绘制。
WARNING
误区 6:以为 MVT 和 WFS 是同一回事。 ✅ 正确:MVT 是预切片的矢量瓦片(按 z/x/y 切,PBF 二进制编码),高并发场景用;WFS 是动态查询(按 BBOX + CQL_FILTER 实时返回),适合低频但灵活的矢量交互。
WARNING
误区 7:以为图层数量没有上限。
✅ 正确:每多一层 fragment shader 多嵌套一次 mix(),性能线性下降。Web GIS 引擎通常限制最多 8 层活动图层。
延伸阅读与自测
权威参考
- OGC Standards — OGC 全部标准官方入口
- OGC WMS 1.3.0 Spec — WMS 标准原文
- OGC WMTS 1.0.0 Spec — WMTS 标准原文
- OGC WFS 2.0 Spec — WFS 标准原文
- Mapbox Vector Tile Spec — MVT 标准仓库
- Wikipedia — Web Map Service — WMS 综述
- Wikipedia — Tiled web map — 栅格瓦片综述
- Web GIS: Principles and Applications — Pinde Fu — Web GIS 教材(第 5 章图层与协议)
自测题
- 协议选型:要做一个”实时空气质量地图”,数据每 5 分钟更新一次,全国范围。会选 XYZ / WMS / WMTS / WFS / MVT 哪个?为什么?
- 混合模式选择:要把”地形阴影”层叠加到”卫星图”层上,让山的立体感更强。选 Normal / Multiply / Screen / Overlay 哪个?为什么?
- WMS vs WMTS:同一个 OGC 服务的 WMS 和 WMTS 接口,请求 1000 次同一个区域,哪个更快?为什么?WMTS 的”快”付出了什么代价?
- MVT vs WFS:为什么 Mapbox 选 MVT 而不是 WFS?两者都是矢量协议,根本差异是什么?
- HTTP/2 与域名分片:你接手了一个老瓦片服务(用
a/b/c.tile.example.com子域名分片)。现在 CDN 升级到 HTTP/2,要不要保留域名分片?为什么?
下一篇导引:05 地形与 Worker 将打开瓦片的第三个维度——高程。DEM 数据怎么编码(RGB / BIL)?大地水准面与椭球面差 ±100 m 怎么修正?Web Worker 如何让地形解码不阻塞渲染?