Cesium.js 学习笔记与可复用效果速查

整理了本地 G 盘全部 Cesium 学习资料——入门课程(30 节)、特效示例集(300+ 案例)、三个 Vue3 项目、mars3d 示例库,加上 3DTiles 倾斜模型和宜兴本地瓦片数据,提炼出速查模板、API 速查和可直接复用的展示效果。写三维 GIS 需求时直接抄。

一、速查模板(直接抄)

1. Viewer 初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import * as Cesium from 'cesium'

// 关闭 Ion 账号提示(用本地数据/自己的 token)
// Cesium.Ion.defaultAccessToken = 'your-token'

const viewer = new Cesium.Viewer('cesiumContainer', {
// 按需关闭不需要的控件,省得遮挡
sceneModePicker: false, // 2D/3D 切换
baseLayerPicker: false, // 底图切换
navigationHelpButton: false, // 操作说明
animation: false, // 时间轴播放
timeline: false, // 时间轴
fullscreenButton: false, // 全屏
infoBox: false, // 实体详情框
// shouldAnimate: true, // CZML 动画需要开
})
// 隐藏 logo
viewer.cesiumWidget.creditContainer.style.display = 'none'

// 飞到指定位置
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(113.3301, 23.0991, 1500),
orientation: {
heading: Cesium.Math.toRadians(-45),
pitch: Cesium.Math.toRadians(-30),
roll: 0,
},
duration: 2,
})

2. 底图加载(XYZ 瓦片 / 天地图)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// XYZ 瓦片服务(本地 http-server 发布的瓦片目录也行)
viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: 'http://localhost:8080/{z}/{x}/{y}.jpg', // 本地宜兴瓦片就是这么加载的
maximumLevel: 18,
})
)

// 天地图(需申请 token)
viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: 'https://t{s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的token',
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
})
)

3. 地形加载

1
2
3
4
5
6
7
// 在线地形
const terrain = await Cesium.createWorldTerrainAsync()
viewer.terrainProvider = terrain

// 本地地形(CesiumTerrainProvider 格式,含 layer.json)
const terrain = await Cesium.CesiumTerrainProvider.fromUrl('./terrains/gz')
viewer.terrainProvider = terrain

4. 3DTiles 加载(倾斜摄影)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 加载倾斜模型
const tileset = await Cesium.Cesium3DTileset.fromUrl('./tp101/tileset.json')
viewer.scene.primitives.add(tileset)
viewer.zoomTo(tileset)

// 点击获取瓦片属性(单体化/查询)
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((movement) => {
const picked = viewer.scene.pick(movement.position)
if (picked) {
const properties = picked.getPropertyIds() // 业务属性 id
console.log('选中:', properties)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)

5. Entity 添加(点/线/面/模型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 点(Billboard 图标)
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(113.33, 23.10),
billboard: {
image: '/images/marker.png',
scale: 0.8,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
})

// 线(发光流动线用 PolylineTrailMaterialProperty,见下)
viewer.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights([lon1, lat1, h1, lon2, lat2, h2]),
width: 4,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.15,
taperPower: 1.0,
color: Cesium.Color.CYAN.withAlpha(0.6),
}),
clampToGround: true, // 贴地
},
})

// 面(水域/电子围栏)
viewer.entities.add({
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([...lonsAndLats]),
material: Cesium.Color.CYAN.withAlpha(0.4),
outline: true,
outlineColor: Cesium.Color.CYAN,
},
})

// 模型(glb/gltf)
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(113.33, 23.10, 10),
model: { uri: '/models/plane.glb' },
})

二、API 速查

1. 官方文档直达

入口 地址 说明
官方文档 cesium.com/learn/cesiumjs/ref-doc 完整 API 索引
官方教程 cesium.com/learn 入门教程 + 沙盒示例
代码沙盒 sandcastle.cesium.com 在线运行/改代码,抄示例首选
源码仓库 github.com/CesiumGS/cesium 查实现细节直接搜源码

用法:沙盒(Sandcastle)每个示例左下角可以”改代码 + 运行”,实现细节全在官方示例里。

2. 核心类速查

分类 类/模块 用途
入口 Viewer 三维场景容器,最常用入口
相机 Camera(flyTo/setView/lookAt)、CameraFlightPath 视角控制
坐标 Cartesian3(笛卡尔)、Cartographic(经纬度弧度)、Transforms(坐标变换)、Math.toDegrees/toRadians 坐标换算
底图 ImageryLayer、UrlTemplateImageryProvider、WebMapTileServiceImageryProvider(WMTS) 影像图层
地形 CesiumTerrainProvider、createWorldTerrainAsync 地形加载
3DTiles Cesium3DTileset(fromUrl/fromIonAssetId)、Cesium3DTileStyle 倾斜模型
实体 Entity(point/billboard/label/polyline/polygon/wall/model/ellipsoid)、EntityCollection 高层封装
底层 Primitive(GroundPolylinePrimitive 贴地)、Cesium3DTileFeature 高性能渲染
事件 ScreenSpaceEventHandler、ScreenSpaceEventType(LEFT_CLICK/LEFT_DOUBLE_CLICK/MOUSE_MOVE) 交互拾取
时间 Clock、JulianDate、SampledPositionProperty、CallbackProperty CZML 动画/动态位置
数据 GeoJsonDataSource、KmlDataSource、CzmlDataSource、DataSourceCollection 数据格式加载
材质 Material、MaterialProperty、CustomShader(3DTiles 着色器)、PolylineGlowMaterialProperty 自定义效果
粒子 ParticleSystem、ParticleEmitter 雨雪火烟
分析 Globe(terrainExaggeration 地形夸张)、scene.pick、SceneTransforms 拾取/量算基础

3. 材质自定义速查(MaterialProperty)

自定义动态材质(流动线/扩散圈/雷达)的标准写法,三步:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 第一步:定义 MaterialProperty 类
function PolylineTrailMaterialProperty(color, duration) {
this._definitionChanged = new Cesium.Event()
this._color = color
this._duration = duration
this._time = Date.now()
}
Object.defineProperties(PolylineTrailMaterialProperty.prototype, {
isConstant: { get: () => false }, // 非恒定 → 每帧求值
definitionChanged: { get: () => this._definitionChanged },
color: Cesium.createPropertyDescriptor('color'),
})
PolylineTrailMaterialProperty.prototype.getType = () => 'PolylineTrail'
PolylineTrailMaterialProperty.prototype.getValue = function (time, result) {
result = result || {}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE)
result.time = (Date.now() - this._time) % this._duration / this._duration
return result
}

// 第二步:注册材质(含 GLSL 着色器)
Cesium.Material.PolylineTrailType = 'PolylineTrail'
Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailType, {
fabric: {
type: 'PolylineTrail',
uniforms: { color: new Cesium.Color(1, 0, 0, 0.5), time: 0 },
source: `
czm_material czm_getMaterial(czm_materialInput materialInput) {
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
float t = fract(time);
// 沿 st.s 方向做流动渐变
float alpha = pow(1.0 - abs(st.s - t) * 2.0, 5.0);
material.alpha = alpha * color.a;
material.diffuse = color.rgb;
return material;
}`,
},
translucent: () => true,
})

// 第三步:使用
polyline: {
positions: ...,
width: 4,
material: new PolylineTrailMaterialProperty(Cesium.Color.CYAN, 3000),
}

三、可复用展示效果(按主题速查)

主题 1:智慧城市大屏

效果 实现思路 复用难度
流动线 PolylineTrailMaterialProperty(GLSL 时间偏移) 易
扩散圈 CallbackProperty 动态改半径 + 透明度衰减 易
雷达扫描 CallbackProperty 动态角度生成扇形 wall + 发光圆环 中
电子围栏 polygon 半透明 + wall 光柱 易
建筑白膜/亮灯 3DTiles style 或遍历 tileset 改材质 中
海量图标聚合 CustomDataSource + 聚合或 kdbush 空间索引 中
粒子(雨雪雾火) ParticleSystem + 贴图 中
热力图 heatmap.js 生成 canvas 贴到 Rectangle 中

扩散圈核心代码(CallbackProperty 动态半径):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let radius = 0
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(113.33, 23.10),
ellipse: {
semiMajorAxis: new Cesium.CallbackProperty(() => radius, false),
semiMinorAxis: new Cesium.CallbackProperty(() => radius, false),
material: new Cesium.ColorMaterialProperty(
Cesium.Color.CYAN.withAlpha(0.5)
),
},
})
// 动画:半径递增,到阈值归零
viewer.clock.onTick.addEventListener(() => {
radius += 50
if (radius > 2000) radius = 0
})

雷达扫描核心代码(扇形 wall + 旋转):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 用 eastNorthUpToFixedFrame 转局部坐标 → 计算扫描扇形顶点 → wall 包成 CallbackProperty
// 每次 tick 让 heading += 4,重新算扇形点(项目里完整实现见 radarScan.js)
let heading = 0
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(lon, lat, 0),
wall: {
positions: new Cesium.CallbackProperty(() => {
const pts = calcRadarSector(lon, lat, radius, heading) // 扇形顶点数组
return Cesium.Cartesian3.fromDegreesArrayHeights(pts)
}, false),
material: Cesium.Color.fromCssColorString('#ff3333').withAlpha(0.4),
},
})
viewer.clock.onTick.addEventListener(() => {
heading = (heading + 4) % 360
})

主题 2:倾斜摄影/模型应用

效果 实现思路 复用难度
3DTiles 加载 Cesium3DTileset.fromUrl + zoomTo 易
单体化 点击拾取 → getPropertyIds() 拿业务属性 → 高亮 中
模型压平 官方 Globe 挖除 + 设置高度,或 tileset 偏移 高
CustomShader 给 3DTiles 加动态着色(渐变/闪烁/水面波动) 高
模型插值运动 SampledPositionProperty 采样时间线 中
视频投射 视频 texture 投到建筑面 高

CustomShader 给倾斜模型加动态效果(3DTiles 专用):

1
2
3
4
5
6
7
8
9
10
const customShader = new Cesium.CustomShader({
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
// 按瓦片高度渐变(例如:白膜/限高着色)
float h = czm_approximateTerrainHeight(...); // 或 fsInput.attributes.positionEC.y
material.diffuse = vec3(0.5 + h * 0.01, 0.8, 0.9);
material.alpha = 0.9;
}`,
})
tileset.customShader = customShader

主题 3:空间分析

效果 实现思路 复用难度
可视域分析 相机视角扇形遮挡检测(ViewShed 类) 高
淹没分析 动态提升水面高度 + 水域面渲染 中
方量分析 地形高度差积分(MeasureVolume 类) 高
剖面分析 沿线采样高度生成折线剖面图 中
坡度/坡向 地形 tile 高度差计算 中
量算工具 点线面拾取 + Cartesian3.distance/面积公式 易
反选遮罩 polygon 大外环 + holes 挖孔 + 半透明黑 + 边界线 易
天际线 提取场景轮廓线 高

量算距离核心(拾取 + 距离):

1
2
3
4
5
6
7
8
9
10
11
12
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
const points = []
handler.setInputAction((movement) => {
const cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid)
if (cartesian) {
points.push(cartesian)
if (points.length >= 2) {
const dist = Cesium.Cartesian3.distance(points[0], points[points.length - 1])
console.log('距离:', dist.toFixed(2), '米')
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)

反选遮罩核心代码(外部压暗 + 目标区高亮,项目 map-mask.vue):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1) 目标边界坐标(如省/市界 GeoJSON coordinates)
const arr = features[0].geometry.coordinates[2][0] // 江苏省界环
const pts = []
arr.forEach((p) => pts.push(p[0], p[1]))
const boundary = Cesium.Cartesian3.fromDegreesArray(pts)

// 2) 关键:大外环 polygon + holes 挖出目标区 = 反选蒙版
viewer.entities.add({
polygon: {
hierarchy: {
positions: Cesium.Cartesian3.fromDegreesArray([
80, 0, 80, 89, 179, 89, 179, 0, // 覆盖全图的大外环
]),
holes: [{ positions: boundary }], // 挖掉目标区域,里面不遮
},
material: Cesium.Color.BLACK.withAlpha(0.5), // 外部压暗
},
})
// 3) 目标区边界线(clampToGround 贴地)
viewer.entities.add({
polyline: {
positions: boundary,
width: 4,
material: Cesium.Color.fromCssColorString('#6dcdeb'),
clampToGround: true,
},
})
viewer.flyTo(boundary, { duration: 3 })

主题 4:高级特效

效果 实现思路 复用难度
3D 风场 粒子流 + 网格渲染(cesium-wind.js) 高
海流 流动线束 + 方向箭头 高
体渲染 3D 纹理 + RayMarching 着色器 高
视频投射 video 元素当纹理贴到模型 中
卫星轨迹 CZML 时间线 + 模型采样位置 中
昼夜/天气 场景光源 + 天空盒 + 粒子组合 中
Cesium 融合 Three viewer.scene.primitives.add 接入 Three 场景 高
分屏/卷帘对比 两图层 SplitDirection 左右分 + scene.splitPosition 拖动 易

CZML 时间轴动画(卫星/车辆轨迹):

1
2
3
4
5
const dataSource = await Cesium.CzmlDataSource.load('/data/satellite.czml')
viewer.dataSources.add(dataSource)
viewer.clock.shouldAnimate = true // 关键:开启时间动画
viewer.clock.multiplier = 100 // 时间倍速
viewer.timeline.zoomTo(viewer.clock.currentTime, viewer.clock.stopTime)

分屏/卷帘对比核心代码(两个底图各占一半,拖动分割线切换,项目 split-screen.vue):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1) 左右两个底图分别指定 SplitDirection(影像分层切割)
const left = viewer.imageryLayers.addImageryProvider(imageProviderA) // 如高德 XYZ
left.splitDirection = Cesium.SplitDirection.LEFT
const right = viewer.imageryLayers.addImageryProvider(imageProviderB) // 如天地图 WMTS
right.splitDirection = Cesium.SplitDirection.RIGHT

// 2) 核心一句:scene.splitPosition 决定分割线位置(0-1)
viewer.scene.splitPosition = 0.5

// 3) 拖动分割线实时更新(slider 是绝对定位的 5px 竖线)
const slider = document.getElementById('slider')
let dragging = false
const handler = new Cesium.ScreenSpaceEventHandler(slider)
handler.setInputAction(() => { dragging = true }, Cesium.ScreenSpaceEventType.LEFT_DOWN)
handler.setInputAction((m) => {
if (!dragging) return
const pos = (slider.offsetLeft + m.endPosition.x) / slider.parentElement.offsetWidth
slider.style.left = `${pos * 100}%`
viewer.scene.splitPosition = pos // 0~1
viewer.scene.imagerySplitPosition = pos
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(() => { dragging = false }, Cesium.ScreenSpaceEventType.LEFT_UP)

四、踩坑记录(项目实测)

  1. 忘记开 shouldAnimate:CZML/时间动画不动,第一反应查时钟
  2. 坐标单位:Cartographic 是弧度,fromDegrees 是度,混用直接偏到海里
  3. 贴线不贴地:polyline 要用 GroundPolylinePrimitive 或 clampToGround: true,否则线可能穿地形
  4. 拖底图白屏:UrlTemplateImageryProvider 的 url 模板 {z}/{x}/{y} 顺序要和瓦片目录一致
  5. 地形瓦片格式:本地地形必须是 CesiumTerrainProvider 格式(含 layer.json),DEM 原片要先用工具切片
  6. 3DTiles 白模/黑模:检查 maximumScreenSpaceError 和光照,瓦片数据本身坐标错位(gltfUpAxis)也会导致整体翻转
  7. 模型不发亮:贴图颜色空间/PBR 材质参数,或需要 lighting 配合
  8. 内存/性能:大场景要关 requestRenderMode(或反过来开)控制渲染频率,海量 entity 用 Primitive/CustomDataSource 而不是一个个 entity
  9. token 提示:不用 Ion 也要设 Ion.defaultAccessToken(可填自己的),否则弹横幅
  10. 销毁:切页 viewer.destroy(),ScreenSpaceEventHandler.destroy(),否则事件泄漏

五、总结

  1. Cesium 三件套:底图(ImageryLayer)+ 地形(TerrainProvider)+ 数据(Entity/Primitive/3DTiles),所有场景都是这三层拼的
  2. 动态效果 = MaterialProperty + CallbackProperty:会写自定义材质就能做流动线、雷达、扩散圈这些”会动”的效果
  3. 分析功能是项目加分项:可视域、淹没、方量这些虽然难,但才是三维 GIS 区别于”3D 看模型”的核心价值
  4. 性能靠 Primitive:entity 好用但多则卡,海量数据必须下沉到底层 Primitive
  5. 本地数据就是题库:本地 3DTiles 倾斜模型(tp101)+ 影像瓦片 + 地形数据,直接拿来练手,不用再找数据

内容由 AI 生成,仅供参考。本文发布于 码上学习,转载请注明出处。