Cesium动态路径实战:用无人机模型玩转3D地球

1,501 阅读4分钟

关键词: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.52.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 // 拖尾时间
  }
})

🎉 项目成果

最终效果:

image.png

动手挑战:尝试修改路径点坐标或调整multiplier值,观察动画变化!

🧠 扩展思考

1. 实时数据对接

将静态路径点替换为WebSocket实时数据流,即可实现:

  • 物流车辆追踪
  • 气象雷达动态路径
  • 卫星轨道模拟

2. 多实体协同

通过创建多个实例,实现:

  • 无人机编队飞行
  • 交通流量模拟
  • 灾害扩散预测

3. 性能优化

  • 使用Primitive替代Entity处理大规模动态数据
  • 启用requestRenderMode减少不必要的重绘
  • 通过Cesium3DTileset加载复杂模型

📘 参考资料

  1. Cesium官方文档
  2. glTF模型格式指南
  3. JulianDate时间计算
  4. Callback Position Property - Cesium Sandcastle

如果你有任何问题,欢迎在评论区留言!让我们一起探索3D地理信息世界的无限可能!