0x01 概述
(1)简介
- CesiumJS 官网链接:https://cesium.com/platform/cesiumjs/
- Cesium 官网链接:https://cesium.com/
- CesiumJS 是基于 JavaScript 与 WebGL 的地图引擎
- 特点:
- 支持 2D、2.5D、3D 形式的地图展示
- 可以自绘图形、高亮区域
- 支持跨端应用
(2)注册
- 访问 https://ion.cesium.com/signup/ 免费注册账号
- 注册完成并登录后,访问 https://ion.cesium.com/tokens 获取认证令牌
(3)创建项目
-
使用命令
npm init -y
快速初始化一个 NodeJS 环境 -
使用命令
npm install cesium
安装 CesiumJS当前版本为 1.124.0
-
在项目根目录下,创建 index.html
<!DOCTYPE html> <html> <head> <script src="./node_modules/cesium/Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./node_modules/cesium/Build/Cesium/Widgets/widgets.css" /> <style> html, body { margin: 0; padding: 0; } body { width: 100vw; height: 100vh; } .cesium-widget-credits { display: none !important; } </style> </head> <body> <div id="cesiumContainer"></div> <script src="./main.js"></script> </body> </html>
-
在项目根目录下,创建 main.js
// 导入令牌 Cesium.Ion.defaultAccessToken = "xxx"; // 创建地球视图 const viewer = new Cesium.Viewer("cesiumContainer"); // 通过 ID 绑定 dom 元素
-
通过 Live Server 之类的插件查看页面
0x02 重要类
(1)查看器
-
查看器(Viewer)是展示三维内容的主要窗口,其中包括视窗、基础控件等
-
查看器使用特定的构造函数定义:
new Cesium.Viewer(container: Element | string, options?: Viewer.ConstructorOptions)
-
举例:
const viewer = new Cesium.Viewer("cesiumContainer", { animation: false, // 关闭动画组件与左下角仪表 timeline: false, // 关闭时间轴 fullscreenButton: false, // 关闭全屏按钮 geocoder: false, // 关闭查找控件 homeButton: false, // 关闭视角返回初始位置按钮 sceneModePicker: false, // 关闭视角模式选择 baseLayerPicker: false, // 关闭图层选择 navigationHelpButton: false, // 关闭帮助 // ... });
(2)场景
-
场景(Scene)是所有图形对象的容器,在查看器内隐式创建
-
在场景中设置图层等价于在查看器中设置图层:
viewer.imageryLayers === viewer.scene.imageryLayers
-
举例:
// 关闭地球 // viewer.scene.globe.show = false; // 设置相机位置 viewer.scene.camera.setView({ destination: Cesium.Cartesian3.fromDegrees( 116.39, // 经度 39.9, // 纬度 1500 // 高度 ), orientation: { heading: Cesium.Math.toRadians(0), // 航向角 pitch: Cesium.Math.toRadians(-30), // 俯仰角 roll: 0, // 滚转角 }, });
(3)实体
-
实体(Entity)用于专注数据的呈现,而不必考虑底层的可视化机制
- 由 Primitive 封装而来,不属于 Scene
-
举例:
// 添加实体 const entity = viewer.entities.add({ name: "中国", position: Cesium.Cartesian3.fromDegrees( 116.39, // 经度 39.9, // 纬度 500 // 高度 ), point: { pixelSize: 10, // 尺寸 color: Cesium.Color.RED, // 颜色 }, }); viewer.trackedEntity = entity; // 跟踪实体对象
(4)数据源
-
数据源(Data Source Collection)是 Cesium 中加载矢量数据的主要方式之一
-
支持加载矢量数据集和外部文件的调用
- CZML:
CzmlDataSource
- KML:
KmlDataSource
- GeoJSON:
GeoJsonDataSource
- CZML:
-
举例:
// 在地球上标记中国地图 viewer.dataSources.add( Cesium.GeoJsonDataSource.load("https://geojson.cn/api/china/china.topo.json") );
0x03 坐标
(1)坐标概述
-
Cesium 有 5 种坐标系:
-
WGS84 经纬度坐标系
-
WGS84 弧度坐标系(
\[弧度 = \frac {\pi × 经纬度角度}{180} \\\\ 经纬度角度 = \frac {180 × 弧度}\pi \]new Cesium.Cartographic(经度, 纬度, 高度)
) -
平面坐标系(
new Cesium.Cartesian2(横坐标, 纵坐标)
) -
笛卡尔空间直角坐标系(
new Cesium.Cartesian3(x 坐标, y 坐标, z 坐标)
) -
4D 笛卡尔坐标系(
Cartesian4
)
-
-
WGS84(World Geodesic System 1984)是为 GPS 使用而建立的坐标系统
- 坐标原点:地球质心
- \(X\) 轴:从原点指向 BIH 1984.0 定义的零子午面和 CTP 赤道的交点
- \(Y\) 轴:由 \(X\) 轴和 \(Z\) 轴通过右手定则确定
- \(Z\) 轴:从原点指向 BIH 1984.0 定义的协议地球极
-
平面坐标系又称屏幕坐标系
- 坐标原点:屏幕左上角
- \(X\) 轴:水平方向,右为正方向
- \(Y\) 轴:垂直方向,下为正方向
-
笛卡尔空间直角坐标系
- \(X\) 轴、 \(Y\) 轴与 \(Z\) 轴两两垂直,并交于同一点
(2)坐标转换
-
经纬度与弧度
var radians = Cesium.CesiumMath.toRadians(degrees); var degrees = Cesium.CesiumMath.toDegrees(radians);
-
WGS84 经纬度坐标与 WGS84 弧度坐标
-
构造函数法:
new Cesium.Cartographic(经度/弧度, 纬度/弧度, 高度)
-
静态函数法:
var cartographic = Cesium.Cartographic.fromDegrees(经度角度, 纬度角度, 高度); var cartographic = Cesium.Cartographic.fromRadians(经度弧度, 纬度弧度, 高度);
-
-
WGS84 坐标系与笛卡尔空间直角坐标
-
WGS84 坐标系 ➡️ 笛卡尔空间直角坐标
-
直接转换
var cartesian3 = Cesium.Cartesian3.fromDegrees(经度, 纬度, 高度); var cartesian3 = Cesium.Cartesian3.fromDegreesArray([经度1, 纬度1, 经度2, 纬度2, ]); var cartesian3 = Cesium.Cartesian3.fromDegreesArrayHeights([经度1, 纬度1, 高度1, 经度2, 纬度2, 高度2, ]);
-
间接转换
var wgs84 = Cesium.Cartographic.fromDegrees(经度, 纬度, 高度); // var wgs84 = Cesium.Cartographic.fromRadians(经度弧度, 纬度弧度, 高度); var cartesian3 = Cesium.Ellipsoid.WGS84.cartographicToCartesian(wgs84); var cartesian3s = Cesium.Ellipsoid.WGS84.cartographicToCartesianArray([wgs84_1, wgs84_2, ]);
-
-
笛卡尔空间直角坐标 ➡️ WGS84坐标系
var cartographic = Cesium.Cartographic.fromCartesian(cartesian3); var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3); var cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray([cartesian1, cartesian2, ...]);
-
-
平面坐标与其他坐标系
- 平面坐标 ➡️ WGS84 坐标系:
var cartesian3 = viewer.scene.pickPosition(Cartesian2);
- 平面坐标 ➡️ 地表坐标:
var cartesian3 = viewer.scene.globe.pick(viewer.camera.getPickRay(Cartesian2), viewer.scene);
- 平面坐标 ➡️ 椭球面坐标:
var cartesian3 = viewer.scene.camera.pickEllipsoid(Cartesian2);
- 笛卡尔空间直角坐标 ➡️ 平面坐标:
var cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene.cartesian3);
- 平面坐标 ➡️ WGS84 坐标系:
0x04 相机系统
(1)相机概述
- 相机用于观察场景,通过改变相机位置实现场景变换
- 对于三维场景中的相机设置,需要考虑相机位置与观察方向
(2)常用相机设置方法
-
setView
:直接定位至目标const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1500); const direction = { heading: Cesium.Math.toRadians(0), // 绕 Y 轴旋转,0 为正北 pitch: Cesium.Math.toRadians(-90), // 绕 X 轴旋转,-90 为俯瞰地面 roll: 0, // 绕 Z 轴旋转,0 为无旋转 }; // 设置相机 viewer.camera.setView({ destination: position, // 相机位置 orientation: direction, // 观察方向 });
-
flyTo
:从空中飞行,逐步定位至目标const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1500); const direction = { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }; // 设置相机 viewer.camera.flyTo({ destination: position, // 相机位置 orientation: direction, // 观察方向 duration: 5, // 持续时间,单位为秒,未设置则默认 1 秒 });
-
lookAt
:与setView
类似,但相机只能在半球形上旋转,中心视点目标不变const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9); const offset = new Cesium.HeadingPitchRange( Cesium.Math.toRadians(0), // heading Cesium.Math.toRadians(-90), // pitch 2500 // range,距离,单位为米 ); // 设置相机 viewer.camera.lookAt(position, offset);
-
viewBoundingSphere
:与lookAt
类似,但相机允许全球形上旋转,并且其中心视点可以不是地面const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1500); const sphere = new Cesium.BoundingSphere( position, // 设置球心位置,即视点 1000 // 设置球半径,即与视点的距离 ); const offset = new Cesium.HeadingPitchRange(0, 0, 0); // 设置相机 viewer.camera.viewBoundingSphere(sphere, offset);
0x05 空间数据
-
空间数据主要包括:
- 栅格数据:如地图、地形
- 矢量数据:如建筑体、几何体
-
Cesium 官方提供了多种空间数据资产,需要在登录官网后开启使用权限,步骤如下:
- 登录至 Cesium ion
- 从官网进入 OPEN ION
- 在菜单栏选择 Asset Depot
- 在列表中选择需要添加的资产,如 Earth at Night,点击该项最右侧的加号即可添加
- 在菜单栏选择 My Assets 确认是否添加成功
(1)载入
a. 地图图层
加载地图图层需要通过查看器添加
-
载入官网提供的地图图层资产
// 从 ion 获取图层 const imageryLayer = Cesium.ImageryLayer.fromProviderAsync( Cesium.IonImageryProvider.fromAssetId(3812) // 3812 是 Earth at Night 资产的 ID ); // 添加图层 viewer.imageryLayers.add(imageryLayer);
-
载入其他地图图层资产,如 ArcGIS
// 从 ArcGIS 获取图层 const imageryLayer = Cesium.ImageryLayer.fromProviderAsync( Cesium.ArcGisMapServerImageryProvider.fromUrl( "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer" ) ); // 添加图层 viewer.imageryLayers.add(imageryLayer);
b. 地形
-
在官网获取地形资产 ArcticDEM Release 4
-
重置相机
viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(86.92, 28, 15000), // 珠穆朗玛峰坐标 orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }, });
-
载入地形
Cesium.CesiumTerrainProvider.fromIonAssetId( // 从 ion 获取地形 3956, // 获取官方提供的地形数据 ID { requestVertexNormals: true, // 可以获取法线,用于计算光照 requestWaterMask: true, // 可以获取水面特效 } ).then((terrainProvider) => { viewer.terrainProvider = terrainProvider; // 添加地形 });
c. 建筑体
-
在官网获取建筑体资产 Cesium OSM Buildings
-
重置相机
viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(121.49, 31.23, 3000), // 上海坐标 orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }, });
-
导入建筑体
Cesium.Cesium3DTileset.fromIonAssetId( // 从 ion 获取建筑体 96188 // 获取官方提供的建筑体数据 ID ).then((tileSet) => { viewer.scene.primitives.add(tileSet); // 添加建筑体 });
d. 自定义
-
重置相机
viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1500), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }, });
-
载入点
viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.382, 39.9), point: { color: Cesium.Color.RED, // 点的颜色 pixelSize: 10, // 点的像素大小 }, description: "这是一个点", // 点的描述,被选中后在右侧弹框显示 });
-
载入线
viewer.entities.add({ polyline: { positions: Cesium.Cartesian3.fromDegreesArray([ 116.382, 39.9, 116.386, 39.9, 116.386, 39.903, ]), // 线的坐标点,依次连接 width: 5, // 线的宽度 material: Cesium.Color.BLUE, // 线的颜色 }, });
-
载入面
viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.39, 39.9), // 面的中心点 plane: { plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Z, 0), // 面的朝向,如 Z 轴平铺(轴向参考笛卡尔空间直角坐标系) dimensions: new Cesium.Cartesian2(400, 300), // 面的尺寸,400 长,300 宽 material: Cesium.Color.GREEN.withAlpha(0.5), // 面的颜色,半透明绿色 outline: true, // 是否显示轮廓线 outlineColor: Cesium.Color.BLACK, // 轮廓线的颜色 }, });
-
载入体
const model = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.396, 39.9), // 模型的位置 orientation: Cesium.Transforms.headingPitchRollQuaternion( Cesium.Cartesian3.fromDegrees(116.396, 39.9), // 模型的位置 new Cesium.HeadingPitchRoll(-90, 0, 0) // 模型的朝向 ), model: { uri: "https://sandcastle.cesium.com/SampleData/models/CesiumAir/Cesium_Air.glb", // 模型地址 minimumPixelSize: 128, // 模型最小像素尺寸 maximumScale: 20000, // 模型最大缩放比例 scale: 10, // 模型缩放比例 show: true, // 模型是否显示 }, }); // viewer.trackedEntity = model; // 将视口快速绑定到模型位置
-
载入文字
viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(116.39, 39.902), // 文字的位置 label: { text: "CesiumJS - SRIGT", // 文字内容 font: "30px sans-serif", // 文字样式,包括字号和字体 style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 文字样式 outlineWidth: 2, // 文字轮廓线宽度 outlineColor: Cesium.Color.BLACK, // 文字轮廓线颜色 fillColor: Cesium.Color.WHITE, // 文字填充颜色 }, });
(2)管理
-
空间数据管理:对数据的增加、查找、修改、删除等
-
举例:
-
创建并增加一个长方体
viewer.entities.add({ id: "myPolygon", polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ 116.382, 39.8995, 116.398, 39.8995, 116.398, 39.9005, 116.382, 39.9005, ]), material: Cesium.Color.RED.withAlpha(0.5), height: 100, // 距离地面高度 extrudedHeight: 200, // 拉伸高度 closeTop: false, // 顶部是否关闭 closeBottom: false, // 底部是否关闭 }, });
-
查找并获取这个长方体(根据 id 查找)
const myPolygon = viewer.entities.getById("myPolygon");
-
修改长方体
- 材质修改为半透明蓝色
- 添加描述
// 修改材质 myPolygon.polygon.material = Cesium.Color.BLUE.withAlpha(0.5); // 添加描述 myPolygon.description = ` <div> <div>id: ${myPolygon.id}</div> </div> `;
-
删除
viewer.entities.remove(myPolygon); // 删除指定数据 viewer.entities.removeAll(); // 删除全部数据
-
0x06 鼠标交互
-
Cesium 提供了多种获取不同对象的方法:
scene.pick
:返回包含给定窗口位置基元的对象scene.drillpick
:返回给定窗口位置所有对象的列表Globe.pick
:返回给定光线和地形的交点
-
Cesium 提供了多种鼠标监听的方法(
ScreenSpaceEventType
枚举类型):LEFT_DOWN
:左键长按LEFT_UP
:左键释放LEFT_CLICK
:左键点击LEFT_DOUBLE_CLICK
:左键双击RIGHT_DOWN
:右键长按RIGHT_UP
:右键释放RIGHT_CLICK
:右键点击MIDDLE_DOWN
:中键长按MIDDLE_UP
:中键释放MIDDLE_CLICK
:中键点击MOUSE_MOVE
:鼠标移动WHEEL
:鼠标滚轮PINCH_START
:双指开始PINCH_END
:双指结束PINCH_MOVE
:双指移动
-
举例:
-
准备相机与被交互的物体
// 相机 viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1500), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0, }, }); // 长方体 viewer.entities.add({ id: "myPolygon", polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ 116.386, 39.8995, 116.394, 39.8995, 116.394, 39.9005, 116.386, 39.9005, ]), material: Cesium.Color.RED.withAlpha(0.5), height: 100, extrudedHeight: 200, }, });
-
实例化事件处理器
const handler = new Cesium.ScreenSpaceEventHandler( viewer.scene.canvas // 获取查看器的场景中所有 Canvas 创建的元素 );
-
监听左键点击事件
handler.setInputAction( (movement) => { const pickedObject = viewer.scene.pick(movement.position); // 获取鼠标移动位置的元素 if ( Cesium.defined(pickedObject) && // 判断被选中的元素是否定义 Cesium.defined(pickedObject.id.id === "myPolygon") // 判断被选中的元素是否是 myPolygon ) { alert("点击了长方体"); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK // 鼠标左键点击事件 );
-
0x07 额外系统
(1)时间系统
-
Cesium 提供了时间系统,主要用于动态数据可视化
-
Cesium 的时间控件
clock
由以下控件组成:animation
:控制时间的启停,默认处于暂停状态timeline
:控制时间线
-
举例:
-
启动并设置播放速度
viewer.clock.shouldAnimate = true; viewer.clock.multiplier = 1000;
-
定义时间范围并缩放时间线
const start = Cesium.JulianDate.fromIso8601("2025-01-01T00:00:00Z"); const end = Cesium.JulianDate.fromIso8601("2025-01-01T01:00:00Z"); viewer.timeline.zoomTo(start, end);
-
(2)粒子系统
-
Cesium 提供了粒子系统,主要用于实现更逼真的仿真模拟
- 如烟花特效、天气效果、车辆尾气
-
Cesium 的粒子系统是一种模拟复杂物理效应的图形技术,其原理为:通过多个小图像集合成一个模糊对象,来产生特效
-
粒子系统使用步骤:
graph LR 设置粒子样式-->通过粒子发射器发射粒子-->控制粒子在一定时间内存在后消亡 -
Cesium 提供了多种粒子发射器:
CircleEmitter
:圆形发射器,参数为半径(number),在圆范围内向上随机发射粒子BoxEmitter
:盒型发射器,参数为盒体积(Cartesian3
),在盒内随机生成粒子
-
举例:火焰粒子特效
// 添加模型 const myPolygon = viewer.entities.add({ id: "myPolygon", polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ 116.386, 39.8995, 116.394, 39.8995, 116.394, 39.9005, 116.386, 39.9005, ]), material: Cesium.Color.RED.withAlpha(0.5), height: 100, extrudedHeight: 200, }, }); // 开启时间系统 viewer.clock.shouldAnimate = true; viewer.clock.multiplier = 1; const start = Cesium.JulianDate.fromIso8601("2025-01-01T00:00:00Z"); const end = Cesium.JulianDate.fromIso8601("2025-01-01T01:00:00Z"); viewer.timeline.zoomTo(start, end); viewer.scene.primitives // 使用 primitives 载入数据 .add( new Cesium.ParticleSystem({ // 实例化一个粒子系统 image: "https://sandcastle.cesium.com/SampleData/fire.png", // 粒子样式图 imageSize: new Cesium.Cartesian2(20, 20), // 粒子大小 startScale: 1.0, // 粒子开始大小 endScale: 4.0, // 粒子结束大小 particleLife: 5.0, // 粒子生命期 speed: 5.0, // 粒子速度 emitter: new Cesium.CircleEmitter(0.5), // 粒子发射器 emissionRate: 5.0, // 粒子发射速率 modelMatrix: myPolygon.computeModelMatrix( // 粒子系统位置 viewer.clock.startTime, // 粒子发射时间 new Cesium.Matrix4() // 粒子发射矩阵 ), lifetime: 16.0, // 粒子系统生命周期 }) );
0x08 数据格式
(1)三维数据 3DTiles
-
3D Tiles 是 Cesium 定义的一种三维模型瓦片数据结构
- 通过分块、分层的形式组织大量三维数据
- 提供多细节层次(LOD)功能,根据距离远近,降低非重要物体的面数和细节度,从而获得高效率的渲染运算
-
特点
- 开放性:根据实际需求设定三维模型的大小与范围,并且可以适配多种空间分区方案,如四叉树(二维平面)、八叉树(三维立体)
- 异质性:可以兼容多种三维模型数据,如普通模型数据、倾斜摄影数据、自绘几何数据等
- 可交互性:支持对单个模型的拾取交互与样式修改
- 专为三维可视化设计:结合图形领域技术,在不同情况下,能够降低渲染计算量、减少 WebGL 绘制请求数量
-
3DTiles 文件以 JSON 配置文件与瓦片数据文件存储
-
官方案例:https://sandcastle.cesium.com/?src=3D Tiles BIM.html&label=3D Tiles
-
载入 3D Tiles 文件:
viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: "./tileset.json", maximumScreenSpaceError: 2, // 最大屏幕空间误差 maximumNumberOfLoadedTiles: 1000, // 最大加载瓦片数量 // ... }) );
(2)动态数据 CZML
-
CZML 是一种基于 JSON 的格式,用于描述时间动态图形场景
-
特点:
- 动态:通过插值算法计算动态变化
- 高效、增量流式传输
- 紧凑且易于解析
- 开放性
- 可扩展性
-
官方案例:https://sandcastle.cesium.com/?src=CZML Box.html&label=CZML
-
载入 CZML 文件:
Cesium.CzmlDataSource.load("./czml.json").then((czmlDataSource) => viewer.dataSources.add(czmlDataSource) );
-End-
标签:const,Cartesian3,viewer,CesiumJS,fromDegrees,Cesium,new From: https://www.cnblogs.com/SRIGT/p/18636762