WebGL 系列——(五)Cesium 轨迹回放专场

1,568 阅读2分钟

一、概念

  • 只要你做地图相关开发,一定会在工作中遇到需要轨迹回放的情况。
  • so,什么是轨迹回放?我的理解:把一个物体在一个时间段内移动过的路径绘制出来,并且还原这个物体沿轨迹移动的动画,就是轨迹回放。

二、思路

(一)首先得有一个路径

  • 路径就按坐标点依次绘制就行,但是会涉及到一个问题,就是如果传进来的路径空隙太大,会出现模型在两个点之间瞬移的现象,所以要对路径进行插值处理。
  • 在这里有一个插件gsap:是一个从flash时代一直发展到今天的专业动画库。速度快。GSAP专门优化了动画性能,使之实现和CSS一样的高性能动画效果。轻量与模块化。模块化与插件式的结构保持了核心引擎的轻量,TweenLite包非常小(基本上低于7kb)。GSAP提供了TweenLite, TimelineLite, TimelineMax 和 TweenMax不同功能的动画模块,你可以按需使用。没有依赖灵活控制。不用受限于线性序列,可以重叠动画序列,你可以通过精确时间控制,灵活地使用最少的代码实现动画。

(二)动起来

  • cesium 中实现动画必须用到时间轴,物体的状态与时间联动就能实现动画效果。

三、实现

  • 创建时间轴 --> 创建实体 --> 在实体中添加定时器、位置、模型、轨迹路线 --> 开启时钟并把视野跟随到模型上

  • 以下是一段项目中实现轨迹回放的真实代码

 // 仿真初始化
  const initSimulation = simulationData => {
    const start = Cesium.JulianDate.fromDate(new Date(simulationData.startTime)); //开始时间
    const stop = Cesium.JulianDate.fromDate(new Date(simulationData.endTime)); //结束时间
    viewer.clock.startTime = start.clone(); //设置cesium时钟开始时间
    viewer.clock.stopTime = stop.clone(); //设置cesium时钟结束时间
    viewer.timeline.zoomTo(start, stop); //设置时间轴的起止时间
    viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //设置播放类型为循环播放
    const position = computeFlight(simulationData, start); //使用差值算法计算路径所需要的动画时长
    //创建一个新的实体
    entity = viewer.entities.add({
      //定时器集合
      availability: new Cesium.TimeIntervalCollection([
        //把刚刚设置的开始结束时间传进来
        new Cesium.TimeInterval({
          start,
          stop,
        }),
      ]),
      position, //把刚刚差值算法计算的结果传进来
      orientation: new Cesium.VelocityOrientationProperty(position), //自动计算角度
      //导入模型
      model: {
        uri: './libs/models/crazyflie.glb', //模型路径
        scale: 1, //缩放比例
        minimumPixelSize: 90, //模型缩小到多少像素后,不再能被缩小
      },
      //绘制轨迹
      path: {
        resolution: 1,//将路径显示为以1秒为增量采样的路径线
        //设置材质
        material: new Cesium.PolylineGlowMaterialProperty({
          glowPower: 1,
          color: Cesium.Color.YELLOW,
        }),
        width: 10,//设置宽度
      },
    });
    viewer.clock.shouldAnimate = true;//开启时钟
    viewer.trackedEntity = entity;//视角会锁定到设定目标实体
  };

  //差值算法(类似 threejs 或者其他地方使用 gsgp )
  const computeFlight = (simulationData, start) => {
    const property = new Cesium.SampledPositionProperty();
    simulationData.routes.forEach((item, i) => {
      const time = Cesium.JulianDate.addSeconds(start, i * 5, new Cesium.JulianDate());
      const position = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 50);
      property.addSample(time, position);
    });
    return property;
  };