CesiumJS 地理空间 3D 开发 🔥 热门
从基础地图到数字孪生,从坐标系转换到 3D Tiles,掌握 Web 地理空间开发核心技术
学习时长:约 25 小时 | 前置:JavaScript、WebGL 基础 | 产出:完整 Cesium 项目
一、CesiumJS 概述
什么是 CesiumJS?
CesiumJS 是一个开源 JavaScript 库,用于创建高性能、跨平台、跨浏览器的 3D 地球和地图应用。由 Analytical Graphics, Inc. (AGI) 开发,广泛用于 GIS、数字孪生、无人机、卫星等领域。
CesiumJS
→
WebGL 渲染
→
地理坐标系
→
3D Tiles
→
数据可视化
| 特性 | 说明 |
| 开源免费 | Apache 2.0 协议,商用友好 |
| WebGL 渲染 | 基于 WebGL,GPU 加速 |
| 多数据源 | 支持 WMS、WMTS、KML、GeoJSON、CZML 等 |
| 3D Tiles | 海量 3D 数据流式加载标准 |
| 坐标系支持 | WGS84、Web Mercator、地方坐标系 |
| 时间动态 | 支持时间轴动画 |
二、环境搭建与基础
2.1 快速开始
// 安装
npm install cesium
// Vite 配置
// vite.config.js
import { defineConfig } from 'vite';
import cesium from 'cesium-vite-plugin';
export default defineConfig({
plugins: [cesium()],
resolve: {
alias: {
'cesium': 'cesium/Source/Cesium.js'
}
}
});
// 基础使用
import * as Cesium from 'cesium';
// 设置 Token(申请地址:https://cesium.com/ion/)
Cesium.Ion.defaultAccessToken = 'your_access_token';
// 创建 Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
animation: false, // 动画控件
timeline: false, // 时间轴
baseLayerPicker: false, // 图层选择
geocoder: false, // 地理编码
homeButton: true, // 主页按钮
sceneModePicker: true, // 场景模式
navigationHelpButton: false,
fullscreenButton: true,
vrButton: false
});
// 定位到指定位置
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(116.397, 39.909, 15000000),
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-90),
roll: 0
}
});
2.2 Viewer 核心组件
| 组件 | 说明 |
| scene | Scene 场景,管理 3D 世界 |
| camera | Camera 相机,控制视角 |
| canvas | Canvas 画布,WebGL 渲染目标 |
| clock | Clock 时钟,控制时间 |
| dataSources | 数据源集合 |
| entities | 实体集合 |
| imageryLayers | 影像图层集合 |
| terrainProvider | 地形提供者 |
三、坐标系与空间参考
3.1 常用坐标系
| 坐标系 | 说明 | 使用场景 |
| WGS84 (EPSG:4326) | 经纬度坐标系 | GPS 定位、地理数据 |
| Web Mercator (EPSG:3857) | 墨卡托投影 | 地图瓦片、2D 地图 |
| ECEF | 地心地固坐标系 | 3D 空间计算 |
| ENU | 东北天坐标系 | 局部相对位置 |
3.2 坐标转换
// 经纬度 → 笛卡尔坐标
const cartesian = Cesium.Cartesian3.fromDegrees(
116.397, // 经度
39.909, // 纬度
100 // 高度(米)
);
// 经纬度数组 → 笛卡尔数组
const positions = Cesium.Cartesian3.fromDegreesArray([
116.39, 39.90,
116.40, 39.90,
116.40, 39.91,
]);
// 笛卡尔坐标 → 经纬度
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const lon = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
// 屏幕坐标 → 世界坐标
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((event) => {
const position = viewer.camera.pickEllipsoid(event.position);
if (position) {
const carto = Cesium.Cartographic.fromCartesian(position);
console.log(`选中位置:${Cesium.Math.toDegrees(carto.longitude)}, ${Cesium.Math.toDegrees(carto.latitude)}`);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
四、实体与数据可视化
4.1 Entity API
// 添加点
viewer.entities.add({
name: '北京',
position: Cesium.Cartesian3.fromDegrees(116.397, 39.909),
point: {
pixelSize: 10,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2
},
label: {
text: '北京',
font: '14px sans-serif',
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
outlineColor: Cesium.Color.BLACK,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -10)
}
});
// 添加线
viewer.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([
116.39, 39.90,
121.47, 31.23,
113.26, 23.13
]),
width: 3,
material: Cesium.Color.BLUE
}
});
// 添加面
viewer.entities.add({
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([
116.39, 39.90,
116.40, 39.90,
116.40, 39.91,
116.39, 39.91
]),
material: Cesium.Color.GREEN.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.BLACK
}
});
// 添加 3D 模型
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(116.397, 39.909, 100),
model: {
uri: 'models/Cesium_Air.glb',
minimumPixelSize: 128,
maximumScale: 20000
}
});
4.2 数据源
GeoJSON 加载
// 加载 GeoJSON
const dataSource = await Cesium.GeoJsonDataSource.load('data/china.geojson', {
stroke: Cesium.Color.HOTPINK,
fill: Cesium.Color.PINK.withAlpha(0.5),
strokeWidth: 3
});
viewer.dataSources.add(dataSource);
// 加载 KML
const kmlDataSource = await Cesium.KmlDataSource.load('data/example.kml');
viewer.dataSources.add(kmlDataSource);
// 加载 CZML(时间动态数据)
const czmlDataSource = await Cesium.CzmlDataSource.load('data/example.czml');
viewer.dataSources.add(czmlDataSource);
五、3D Tiles 大规模数据
5.1 3D Tiles 概述
3D Tiles 是 OGC 社区标准,用于流式传输大规模异构 3D 地理空间数据。
倾斜摄影
→
点云
→
BIM 模型
→
矢量数据
5.2 加载 3D Tiles
// 加载 3D Tiles
const tileset = await Cesium.Cesium3DTileset.fromUrl('https://example.com/tileset.json');
viewer.scene.primitives.add(tileset);
// 定位到模型
viewer.zoomTo(tileset);
// 设置样式
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
["\${Height} >= 100", "color('red')"],
["\${Height} >= 50", "color('orange')"],
['true', "color('blue')"]
]
}
});
// 监听加载完成
tileset.allTilesLoaded.addEventListener(() => {
console.log('所有瓦片加载完成');
});
六、相机与飞行控制
6.1 相机控制
// 设置视角
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(116.397, 39.909, 5000),
orientation: {
heading: Cesium.Math.toRadians(0), // 朝向
pitch: Cesium.Math.toRadians(-45), // 俯仰
roll: 0 // 翻滚
}
});
// 飞行到指定位置
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(116.397, 39.909, 5000),
duration: 3, // 飞行时间(秒)
maximumHeight: 10000,
complete: () => { console.log('飞行完成'); }
});
// 飞行到实体
viewer.flyTo(entity, {
duration: 2,
offset: new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(0),
Cesium.Math.toRadians(-45),
1000
)
});
// 原地旋转
viewer.clock.onTick.addEventListener(() => {
viewer.camera.rotate(Cesium.Math.toRadians(0.1));
});
七、高级特效与场景
7.1 天气与大气
// 设置大气效果
viewer.scene.globe.enableLighting = true; // 启用光照
viewer.scene.fog.enabled = true; // 雾效
viewer.scene.skyAtmosphere.hueShift = -0.0;
viewer.scene.skyAtmosphere.saturationShift = 0.1;
viewer.scene.skyAtmosphere.brightnessShift = -0.1;
// 太阳位置(基于时间)
viewer.scene.globe.enableLighting = true;
7.2 后处理效果
// 高亮轮廓
const outlineBlue = new Cesium.PostProcessStageLibrary.createSilhouetteStage();
viewer.scene.postProcessStages.add(outlineBlue);
八、性能优化
优化策略
| 策略 | 说明 |
| 3D Tiles | 使用 3D Tiles 替代普通模型,支持 LOD |
| 实例化 | Primitive API 比 Entity 性能更好 |
| 视锥剔除 | 自动剔除视野外的对象 |
| 按需加载 | 根据相机距离加载不同精度 |
| Web Worker | 复杂计算放到 Worker 中 |
| 纹理压缩 | 使用 KTX2 等压缩格式 |
// 使用 Primitive API 提升性能
const instance = new Cesium.GeometryInstance({
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(116.39, 39.90, 116.40, 39.91),
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5))
}
});
viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance()
}));
九、数字孪生实战架构
完整数字孪生系统架构
┌─────────────────────────────────────────────────┐
│ 前端展示层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ CesiumJS │ │ Three.js│ │ 图表 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────┤
│ 数据接入层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ IoT 数据 │ │ GIS 数据 │ │ 业务数据 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────┤
│ 服务层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 3D Tiles │ │ WebSocket│ │ API │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
十、面试高频问题
Q1:CesiumJS 和 Google Earth 有什么区别?
查看答案 ▼
CesiumJS 是开源库,可以嵌入网页;Google Earth 是独立应用。CesiumJS 更适合开发定制化的 3D 地理应用,支持自定义数据源和交互逻辑。
Q2:3D Tiles 和传统模型加载有什么区别?
查看答案 ▼
- 数据量级:3D Tiles 支持 GB 级数据,传统模型通常 MB 级
- 加载方式:3D Tiles 按需加载(LOD),传统模型一次性加载
- 精度控制:3D Tiles 根据距离自动切换精度
- 标准:3D Tiles 是 OGC 标准,通用性强
Q3:CesiumJS 性能优化的关键点?
查看答案 ▼
- 使用 Primitive API 替代 Entity API
- 3D Tiles 替代普通模型
- 合理使用 requestRenderMode 减少渲染
- 纹理压缩(KTX2/Basis)
- 视锥剔除和遮挡剔除
- Web Worker 处理数据解析