GIS
综合练习
前情回顾:本系列已覆盖从坐标系、瓦片、地形、相机、矢量、渲染管线到 3D Tiles 和调优的完整知识链。本篇是收官,将 Phase 1-10 的核心概念编织成一个可落地的 GIS 应用图景——从”能看到地球”到”能交互的 3D 城市”。
直觉问题
看完前 10 篇,你可能在想:
- 我之前学的知识怎么用在一个真实项目里? Web 墨卡托、四叉树、RTE、Tone Mapping……这些东西是怎么组合起来变成一个能用的产品的?
- 如果我要做一个”某城市 3D 可视化”,需要哪些模块? 哪些是必需的?哪些是可选的?
- 不同框架(CesiumJS / Three.js / Mapbox GL JS)应该怎么选? 它们的适用场景和学习曲线有什么区别?
本篇前 10 篇的知识点进行串联,形成一个完整的应用视角。
核心概念白话讲
用”做一道菜”理解 GIS 应用构建
构建一个 GIS 应用就像做一道完整的宴席——每种食材(数据)和每道工序(模块)都有它的角色。
| 做菜步骤 | GIS 应用模块 | 知识来源 |
|---|---|---|
| 食材准备 | 数据层(影像 / 高程 / 矢量 / 3D 模型) | 04 影像图层 · 05 地形与 Worker |
| 刀工处理 | 调度层(四叉树 LOD、视锥剔除、Worker 管线) | 03 四叉树与 LOD |
| 调味上色 | 渲染层(Shader、Tone Mapping、大气散射) | 08 渲染管线 |
| 摆盘出餐 | 交互层(相机控制、拾取、飞行漫游) | 06 相机与拾取 |
| 点缀装盘 | 矢量标绘层(点、线、面、文字、Billboard) | 07 矢量与实体 |
真实 GIS 应用的”五大要素”
一个最小可用的 3D GIS 应用必须包含:
- 底图(影像瓦片):让用户看到地球表面
- 地形(DEM):让地面有起伏,不是平的
- 相机(交互):让用户能看、能飞、能缩放
- 矢量(标绘):在地图上画点、线、面
- 拾取(Picking):用户点击后知道点到了什么
在此基础上可叠加:
- 3D Tiles(城市建筑模型)→ 09 3D Tiles 与 BIM
- 大气散射(蓝色天空、日落)→ 08 渲染管线
- Tone Mapping(HDR 到 LDR 映射)→ 08 渲染管线
- 性能调优 → 10 调优手册
原理与数学/机制
1. GIS 应用 7 层架构
一个完整的 GIS 应用从上到下可分为 7 个逻辑层级,每一层只与上下层交互:
┌────────────────────────────────────────也不对现的──────┐
│ 7. 用户体验层 │ 飞行动画、过渡特效、响应式反馈 │
├──────────────────┼──────────────────────────────────────┤
│ 6. UI 层 │ HTML/CSS 叠加面板、信息弹窗、图例控件 │
├──────────────────┼──────────────────────────────────────┤
│ 5. 控件层 │ Drawing / Ruler / ElevationProfile / 测量 │
├──────────────────┼──────────────────────────────────────┤
│ 4. 交互层 │ 鼠标/触摸/键盘事件 → Picking → 派发事件 │
├──────────────────┼──────────────────────────────────────┤
│ 3. 渲染层 │ 8步帧循环 → FBO → Tone Mapping → 屏幕输出 │
├──────────────────┼──────────────────────────────────────┤
│ 2. 调度层 │ 四叉树遍历 → LOD选择 → 瓦片请求 → Worker解码 │
├──────────────────┼──────────────────────────────────────┤
│ 1. 数据层 │ XYZ / WMS / BIL / COG / 3D Tiles / GeoJSON │
└──────────────────┴──────────────────────────────────────┘
NOTE
第 1–3 层属于引擎核心(通常用 C++/Rust/WebGL 实现),第 4–7 层则是框架封装的 JavaScript API 层。入门学习时,先掌握上层概念,再逐步深入下层原理。
2. 端到端事件流:从点击到弹窗
用户点击地球上一个点到弹出信息框,经历了哪些关键步骤?
flowchart LR
A[用户点击屏幕 x,y] --> B[射线从相机发出\n进入 Picking FBO]
B --> C[读取 x,y 像素颜色]
C --> D[颜色编码 → Entity ID]
D --> E[查询 Entity 属性表]
E --> F[派发 click 事件]
F --> G[UI 层渲染弹窗]
G --> H[用户看到信息框]
关键用到 Phase 06 相机与拾取中的 Picking 原理:每个 Entity 分配唯一 RGB 颜色,写入独立 FBO,鼠标处颜色直接解码为 ID。
3. 坐标变换链:用户输入到屏幕像素的完整路径
GIS 应用中最频繁的操作之一是”用户输入了一个经纬度,屏幕上该显示在哪里”。这背后是一整串坐标变换:
WGS84 经纬度 (λ, φ, h)
│
▼
WGS84 椭球 → ECEF 地心地固直角坐标 (X, Y, Z)
│
▼
多视锥 RTE 高精度矩阵变换
│
▼
投影矩阵 → NDC 归一化设备坐标 (x, y, z, w)
│
▼
视口变换 → 屏幕像素坐标 (px, py)
其中精度处理是关键难点:
4. Phase 知识索引
| 功能模块 | 涉及核心知识点 | 对应笔记 |
|---|---|---|
| 坐标转换 | WGS84 → ECEF → 屏幕像素;Web 墨卡托投影 | 02 坐标与投影 |
| 瓦片加载 | 四叉树、LOD、SSE 选择策略、视锥/地平线剔除 | 03 四叉树与 LOD |
| 影像叠加 | XYZ/WMS/WMTS、多纹理混合、OGC 标准 | 04 影像图层 |
| 地形渲染 | DEM、RGB/BIL 高程编码、Geoid、Worker 管线 | 05 地形与 Worker |
| 相机交互 | RTE 高精度、多视锥、Picking FBO、Slerp 飞行 | 06 相机与拾取 |
| 矢量标绘 | ECS、GPU 实例化、Billboard、MSDF 字体 | 07 矢量与实体 |
| 大气/光照 | Rayleigh/Mie 散射、Tone Mapping、HDR | 08 渲染管线 |
| 城市模型 | 3D Tiles 标准、BVH 空间索引、地理锚定变换 | 09 3D Tiles 与 BIM |
| 性能优化 | LRU 缓存、帧预算、GPU 分析与工具链 | 10 调优手册 |
5. 飞行动画的数学原理
相机从 A 点飞向 B 点的过程不是简单的线性插值,而是球面线性插值(Slerp)。
设 A、B 是单位球面上的两个三维向量(已归一化),插值参数 t ∈ [0, 1]:
其中 θ = arccos(A·B) 是两点夹角。
TIP
为什么要用 Slerp?因为线性插值在球面上会产生”内凹弧线”,穿过地球内部。Slerp 保证插值轨迹沿大圆最短路径,飞行更符合直觉,不会穿地。
飞行路径还包含 ease-in 和 ease-out 曲线,让速度先加速后减速:
速度
▲
│ ╱╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
└─────────────▶ 时间
加速 减速
6. 完整 GIS 应用的初始化流水线
flowchart TD
A[初始化场景] --> B[加载底图瓦片]
A --> C[加载地形数据高程]
B --> D[建立四叉树索引]
C --> D
D --> E[首帧渲染]
E --> F[激活相机控制器]
F --> G[启用 Picking]
G --> H[进入交互运行态]
H --> I[渲染每一帧更新]
I --> J[异步瓦片加载与调度]
J --> I
对应的模块协作关系:
| 阶段 | 主导模块 | 依赖知识 | 核心任务 |
|---|---|---|---|
| 阶段 1 初始化 | Scene | 全局配置 | 创建 Renderer、Camera、SceneGraph |
| 阶段 2 数据加载 | DataLoader | 瓦片编码、Worker | 并行请求 XYZ/DEM/矢量数据 |
| 阶段 3 索引建立 | Quadtree | 四叉树、LOD | 构建空间索引,分级加载 |
| 阶段 4 首帧渲染 | Rendering Engine | 8 步帧循环 | 渲染底图、地形、大气 |
| 阶段 5 交互就绪 | Interaction | Picking、事件 | 绑定鼠标/键盘/触摸控制器 |
| 阶段 6 运行态 | Main Loop | 帧预算、资源调度 | 持续更新瓦片、相机、Entity |
可视化对比与动手实验
实验 1:5 个典型应用场景
| 场景 | 必需模块 | 可选模块 | 推荐框架 |
|---|---|---|---|
| 城市 3D 可视化 | 底图 + 地形 + 3D Tiles | 大气散射、Tone Mapping | CesiumJS |
| 路径规划导航 | 底图 + 矢量线 + 相机控制 | 实时交通路况 | Mapbox GL JS |
| 人口密度热力图 | 底图 + 热力图层 | 时间轴动画 | deck.gl |
| 航天态势感知 | 底图 + 轨道线 + 3D 模型 | 大气光照、阴影 | CesiumJS |
| 室内精细导航 | 矢量 + 地板分层 + 相机 | 3D Tiles BIM + 剖切 | Three.js |
实验 2:必需 vs 可选模块
| 模块 | 必需/可选 | 说明 |
|---|---|---|
| 底图渲染 | 必需 | 没有底图用户啥也看不到 |
| 地形高程 | 可选 | 平原地区可省略,05 地形讲清 Geoid 与椭球面差异 |
| 相机控制 | 必需 | 没有相机,无法交互浏览 |
| 矢量标绘 | 可选 | 纯浏览场景可省略 |
| Picking 拾取 | 可选 | 不需要点击交互可省略 |
| 3D Tiles | 可选 | 没有精细城市模型可省略 |
| 大气散射 | 可选 | Rayleigh/Mie 仅游戏级渲染需要 |
| Tone Mapping | 可选 | HDR 到 LDR 映射,高画质场景需要 |
| Anti-aliasing | 可选 | 边缘锯齿不明显时可省略 |
| 水面效果 | 可选 | 仅涉及水域场景需要额外实现 |
实验 3:框架选型决策树
是否需要 3D 地球视角?
├── 是 → 需要 3D Tiles 或 BIM 集成?
│ ├── 是 → CesiumJS(原生支持 OGC 3D Tiles 标准)
│ └── 否 → Three.js + 地球球体插件(高度可定制)
└── 否 → 需要海量大数据可视化?
├── 是 → deck.gl(GPU 加速聚合渲染)
└── 否 → 需要严格 OGC 标准支持?
├── 是 → OpenLayers(政企标准首选)
└── 否 → Mapbox GL JS(移动端流畅体验)
实验 4:主流 GIS 框架能力均衡图
用「3D 地球能力」和「数据规模能力」两个维度来看各框架的定位:
3D 地球能力
▲
│
极高 │ CesiumJS ★
│ │
高 │ │ Three.js
│ │ ·
中 │ OpenLayers │
│ · │
低 │ Mapbox deck.gl
│
└────────────────────────────────▶ 数据规模
低 中 高 极高
TIP
CesiumJS 是唯一同时覆盖”3D 地球 + 大数据”双象限的成熟框架,但也最重。 Three.js 更灵活但需自行组装地球、瓦片、相机等模块。 选择框架的核心准则是:先做减法——列出”绝对不可少的功能”,再找最小满足条件的框架。
常见误区
WARNING
误区 1:综合 demo 必须包含 3D Tiles 基础”底图 + 地形 + 矢量”已是完整可交互应用。3D Tiles 是锦上添花,不是必需品。很多场景(如城市公交查询、行政区划浏览)根本不需要精细建模。
WARNING
误区 2:所有功能都从轮子造起 GIS 框架(CesiumJS / Mapbox GL JS)已经封装了大量底层工作,如瓦片调度、相机控制、Picking、坐标转换。你的精力应放在业务逻辑和数据上,而不是从零写四叉树和投影计算。
WARNING
误区 3:demo 越大越好 简洁的 demo 更有教学价值。一个只含”底图 + 相机 + 一个标记点”的 demo,比一个包含 10 个功能的臃肿 demo 更能让人快速理解核心原理。
WARNING
误区 4:CesiumJS = 唯一选择 不同场景匹配不同框架。城市 3D 可视化选 CesiumJS,移动端地图导航选 Mapbox GL JS,大数据可视化选 deck.gl,完全定制化自由渲染选 Three.js。
WARNING
误区 5:Slerp 飞行 = 万能相机运动 Slerp 只保证大圆最短路径,不解决碰撞检测。如果飞行路径穿入地下或建筑内部,需要在插值轨迹上做地形/碰撞避让。实际产品中,先在地面上方保留安全高度,再应用 Slerp。
延伸阅读与自测
延伸阅读
- CesiumJS Tutorials — 最系统的 3D GIS 框架教程,涵盖从入门到 3D Tiles 的完整学习路径:https://cesium.com/learn/
- deck.gl Documentation — 大数据可视化首选,通过 GPU 聚合 10^6+ 点数据:https://deck.gl/
- Mapbox GL JS — 移动端地图开发指南,矢量切片渲染引擎:https://docs.mapbox.com/mapbox-gl-js/
- OpenLayers — 2D 标准地图框架,OGC 标准支持最完整:https://openlayers.org/
- OGC 3D Tiles Specification — 官方标准文档,理解 3D 瓦片组织的权威参考
自测题
1. 设计题
假设你是一个三线城市的智慧交通项目技术负责人,需要构建一个”实时公交监控”系统(在地图上显示所有公交车的实时位置和行驶路线),你会选择哪个框架?为什么?列出必需模块和可选模块。
2. 流程题
用户在地图上点击一个公交站点(Entity),弹窗显示站点信息。画出从”点击”到”弹窗”的完整事件流,并标出每个步骤对应到 Phase 1-10 的知识点。
3. 方案对比
CesiumJS 和 Mapbox GL JS 的核心区别是什么?分别列出 3 个 CesiumJS 更适合的场景和 3 个 Mapbox GL JS 更适合的场景。提示:从”投影方式、数据规模、性能开销、移动端支持”四个维度分析。
4. 数学计算
设相机在单位球面上从 A 点到 B 点,其中 A = (0, 0, 1),B = (1, 0, 0),参数 t = 0.25。
- 先用线性插值计算中间点
P_linear - 再用Slerp计算中间点
P_slerp - 比较两个结果,解释为什么 Slerp 不会穿入地球内部
5. 架构题
设计一个支持 10 万用户同时在线的全球气象监控系统,核心需求包括:
- 实时的全球卫星云图覆盖
- 用户可以在任意位置叠加本地气象站数据(矢量点、温度/湿度图表)
- 支持 VR 模式(沉浸式地球浏览体验)
请回答:
- 技术栈选什么框架?为什么?
- 瓦片数据源如何组织?如何处理高并发下的缓存?
- 全球气象站数据如何索引和渲染?(提示:思考点聚类和 LOD 策略)
- VR 模式下,Picking 和相机控制需要做哪些特殊处理?
下一篇导引:本系列至此完结。建议按照 00 阅读指南 中的学习路径,根据自身掌握程度查漏补缺。如果你要入门 GIS 应用开发,推荐的动手路径是:CesiumJS Hello World → 叠加底图 → 加载 DEM 地形 → 添加简单 Entity → 实现飞行动画 → 接入 3D Tiles。每一步都有对应的笔记知识点支撑,祝你学习顺利!