关键词:Cesium动态路径 | Catmull-Rom样条 | 实时轨迹动画 | 3D地球可视化
🌍 项目背景
在智慧城市、物流追踪、应急指挥等场景中,我们常常需要展示实体对象(如无人机、车辆)的动态路径轨迹。本文将通过一个无人机飞行模拟案例,手把手教你用Cesium实现:
- 平滑的3D飞行路径
- 实时模型姿态调整
- 路径轨迹可视化
- 动画时间控制
🛠️ 技术准备
1. 开发环境
- Node.js + npm/pnpm
- Cesium 1.102+(支持WebGL 2.0)
- 3D模型(推荐使用
.glb格式)
🚀 实现流程详解
第一步:初始化项目
可以选择合适的技术栈,我这里是基于Vite构建的工程,通过pnpm引入Cesium,也可以选择通过CDN或静态文件的方式引入Cesium。
pnpm create vite my-vue-app --template vue-ts
通过Vite/Webpack引入Cesium的时候要处理一些额外的逻辑,例如需要设置静态资源路径、引入widgets.csss等,我们通过插件vite-plugin-cesium处理这些额外的工作,专注业务本身。
pnpm add -D vite-plugin-cesium && pnpm i
配置vite,注册vite-plugin-cesium和其他需要的插件。
import path from 'path'
import { defineConfig } from 'vite'
import cesium from 'vite-plugin-cesium'
export default defineConfig({
base: '/',
plugins: [vue(), cesium()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})
初始化三维场景,关闭Cesium默认开启的一些控件。
const mapID: String = ref('cesium-container')
const viewer: ShallowRef<Viewer | null> = shallowRef(null)
viewer.value = new Viewer(mapID.value, {
terrain: Terrain.fromWorldTerrain(),
// 隐藏控件
animation: false,
baseLayerPicker: false,
geocoder: false,
homeButton: false,
infoBox: false,
sceneModePicker: false,
fullscreenButton: false,
vrButton: false,
selectionIndicator: false,
timeline: true,
navigationHelpButton: false,
navigationInstructionsInitiallyVisible: false,
// 性能优化项
requestRenderMode: false,
scene3DOnly: true,
orderIndependentTranslucency: false,
})
小贴士:记得在HTML中添加
<div id="cesium-container"></div>容器,并设置容器撑满全屏。
第二步:设置动画时间轴
// 定义时间范围
const start = JulianDate.fromDate(new Date(2025, 5, 28, 16))
const stop = JulianDate.addSeconds(start, 8, new Cesium.JulianDate())
// 配置动画控制器
viewer.clock.startTime = start.clone()
viewer.clock.stopTime = stop.clone()
viewer.clock.currentTime = start.clone()
viewer.clock.multiplier = 1.0
viewer.clock.clockRange = ClockRange.LOOP_STOP
viewer.clock.shouldAnimate = true
// 自动缩放时间轴
viewer.timeline.zoomTo(start, stop)
动画控制技巧:通过修改
multiplier值(如0.5或2.0)可调节播放速度。
第三步:构建平滑飞行路径
定义路径点,通过CatmullRomSpline生成轨迹。
// 定义路径点(经纬度+高度)
const points = [
Cartesian3.fromDegrees(-112.87709, 36.27782, 620.01),
Cartesian3.fromDegrees(-112.87351, 36.27992, 617.9),
Cartesian3.fromDegrees(-112.87081, 36.2816, 617.6),
Cartesian3.fromDegrees(-112.86539, 36.28239, 625.36),
Cartesian3.fromDegrees(-112.86108, 36.28137, 627.82),
Cartesian3.fromDegrees(-112.85551, 36.27967, 625.54),
Cartesian3.fromDegrees(-112.848, 36.27732, 628.9),
Cartesian3.fromDegrees(-112.84086, 36.27739, 638.81),
Cartesian3.fromDegrees(-112.83682, 36.27995, 643.31),
]
const before = Cartesian3.fromDegrees(-112.87962, 36.27375, 620.01)
const after = Cartesian3.fromDegrees(-112.83506, 36.2822, 643.31)
const firstTangent = Cartesian3.subtract(points[0], before, new Cartesian3())
const lastTangent = Cartesian3.subtract(after, points[8], new Cartesian3())
// 使用Catmull-Rom样条插值生成平滑曲线
const positionSpline = new CatmullRomSpline({
times: [0, 1, 2, 3, 4, 5, 6, 7, 8], // 时间戳数组
points: points,
firstTangent: Cesium.Cartesian3.subtract(points[0], before, new Cesium.Cartesian3()),
lastTangent: Cesium.Cartesian3.subtract(after, points[8], new Cesium.Cartesian3())
})
原理讲解:Catmull-Rom样条通过相邻四个点计算中间点的切线,使路径自然弯曲。非常适合无人机等需要平滑转向的场景。
第四步:动态位置计算
通过CallbackPositionProperty计算无人机模型的实时位置。
// 创建回调函数实时计算位置
const position = new CallbackPositionProperty(function (time, result) {
const splineTime = (delta * Cesium.JulianDate.secondsDifference(time, start)) / duration
return positionSpline.evaluate(splineTime, result)
}, false)
关键点:
CallbackPositionProperty允许你根据时间动态计算位置,非常适合实时数据驱动的场景。
第五步:添加无人机模型
模型使用了Cesium官方提供的CesiumDrone.glb,确保能够正常加载。我在第三方网站找了一个好看点的无人机模型,结果死活加不上来,切成3D Tiles之后也无法正常显示,还是用官方的比较稳妥。(Cesium有大坑。。。)
viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start, stop })]),
position: position,
orientation: new VelocityOrientationProperty(position), // 自动对齐方向
model: {
uri: "/SampleData/models/CesiumDrone/CesiumDrone.glb", // 3D模型路径
minimumPixelSize: 64, // 最小显示尺寸
maximumScale: 20000 // 最大缩放比例
},
path: {
material: new Cesium.PolylineGlowMaterialProperty({ // 路径发光效果
glowPower: 0.1,
color: Cesium.Color.YELLOW
}),
width: 10,
resolution: 0.01,
leadTime: 1, // 超前显示时间
trailTime: 0.1 // 拖尾时间
}
})
🎉 项目成果
最终效果:
动手挑战:尝试修改路径点坐标或调整
multiplier值,观察动画变化!
🧠 扩展思考
1. 实时数据对接
将静态路径点替换为WebSocket实时数据流,即可实现:
- 物流车辆追踪
- 气象雷达动态路径
- 卫星轨道模拟
2. 多实体协同
通过创建多个实例,实现:
- 无人机编队飞行
- 交通流量模拟
- 灾害扩散预测
3. 性能优化
- 使用
Primitive替代Entity处理大规模动态数据 - 启用
requestRenderMode减少不必要的重绘 - 通过
Cesium3DTileset加载复杂模型
📘 参考资料
如果你有任何问题,欢迎在评论区留言!让我们一起探索3D地理信息世界的无限可能!