Mars3D开发基础:时钟Clock及时序控制

852 阅读5分钟

Mars3D开发基础系列文档导航

  1. 三维场景 Map
  2. 地图控件
  3. 地图图层 Layer
  4. 加载DEM地形
  5. 栅格瓦片图层
  6. 坐标系及坐标变换
  7. 相机Camera及视角控制
  8. 时钟Clock及时序控制
  9. 事件机制
  10. 矢量图层Layer
  11. 矢量数据Graphic
  12. Property属性机制
  13. Material材质
  14. glTF小模型
  15. 3DTiles三维模型
  16. 场景特效
  17. 管理及分析功能

平台的强大之处也在于其可以将时间运用到三维地球上,平台不仅仅是3D的地理空间的展示,同时也具备“时间维度”的时序的相关控制,具备空间+时间的管理,可以根据“时间”进行动画、轨迹记录、地球的光照等等所有与时间相关的可视化效果。

1. 打开时间相关控件

为了更好理解Clock,我们可以在地图中打开2个Cesium内置时钟Clock相关的控件。

//合并属性参数,可覆盖config.json中的对应配置
var mapOptions = mars3d.Util.merge(options, { 
   control: {
       animation: true, //是否创建 动画小器件,左下角仪表
       timeline: true, //是否显示 时间线控件
   },
}) 
//创建三维地球场景
let map = new mars3d.Map('mars3dContainer', mapOptions) 

运行效果:

image.png

2. 时序控制相关对象

2.1 clock时钟对象

map.clock 时钟对象,由三维地图内部创建的Clock类,可以对时间维度做相关控制。

clock对象是一个同步系统时间的一个对象,想要实现时间驱动数据的动态化渲染,都需要clock对象去创建一个时间序列。一般来说电脑屏幕的刷新率都是60hz,cesium定义的是每秒刷新60次,每帧需要的时间大概是16.67mm。

Clock中默认开始时间(startTime)为当前时间,终止时间(stopTime)为24小时后,并能获取当前时间(currentTime)。

clock对象的构造器有以下几个常用属性:

  • map.clock.shouldAnimate = true : 控制开始和停止
  • map.clock.startTime = Cesium.JulianDate.fromIso8601('2017-08-25'):开始时间
  • map.clock.stopTime = Cesium.JulianDate.fromIso8601('2017-08-26'):结束时间
  • map.clock.currentTime = Cesium.JulianDate.fromIso8601('2017-08-25T12:18:20Z') :当前时间
  • map.clock.multiplier= 2.0:时间速率(快速播放与慢速播放),默认1.0
  • map.clock.clockRange = Cesium.ClockRange.UNBOUNDED:表示时间轴达到终点之后的行为, 可选值:CLAMPED 达到终止时间后停止,LOOP_STOP 达到终止时间后重新循环,UNBOUNDED 达到终止时间后继续读秒。

2.2 JulianDate 时间类

Clock内部以儒略日(JulianDate)维护时间。其起始日期为公元前4713年1月1日中午12时,这和我们常用的格林威治时间略有不同,主要是天文学家使用。

JulianDate类提供了非常丰富的接口,时间的对比,运算,和格林威治时间的转换等,简单易用,完全满足各类需求。同时内部还可以采用国际原子时(TAI)的方式来记录。

3. 时序控制的应用

3.1 动态加载时间序列瓦片

所谓时间序列瓦片是指存在多套瓦片,每套瓦片不是单独的,与时间有关。比如我们每天拍摄一遍地球影像,然后把每天的影像都做成一套瓦片,那么一年下来就会有365套瓦片,采用传统方案我们只能写365个页面每个页面加载一天的瓦片。这样非常麻烦,并且没有一个动态变化的效果也无法进行对比。

时间序列瓦片与普通瓦片的区别正在此处。其创建时需要多指定与时间有关的参数。如下:

//interval表示传入的时间区间,index表示是第几个区间,这两个参数也就分割了times中的完整时间段,所以我们可以给time赋值为任意想要设置的值。
function dataCallback(interval, index) {
   console.log(index);
   var time;
   if (index === 0) {
       time = Cesium.JulianDate.toIso8601(interval.stop);
   } else {
       time = Cesium.JulianDate.toIso8601(interval.start);
   }
   //返回的是key、value形式,此处Time为key,而其必须与创建图层时候的{Time}字符串一致,否则请求的时候无法替换时间信息。
   return {
       Time: time
   };
}

var times = Cesium.TimeIntervalCollection.fromIso8601({
   iso8601: '2015-07-30/2017-06-16/P20D', //iso8601参数为时间范围及间隔,用'/'分割,第一个表示开始时间,第二个表示结束时间,P20D表示间隔20天,还可以是P1M、P1Y、P1Y3M5DT6H7M30S等,代表不同的时间间隔。
   leadingInterval: true,
   trailingInterval: true,
   isStopIncluded: false,
   dataCallback: dataCallback //dataCallback表示在每个时间段内如何取值
});

var  tileLayer = new mars3d.layer.WmtsLayer({
   url : 'https://gibs.earthdata.nasa.gov/wmts/epsg4326/{best}/{Layer}/{Style}/{Time}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png', //{TileMatrix}/{TileRow}/{TileCol}表示z、x、y,无需手动设置
   layer : 'AMSR2_Snow_Water_Equivalent',
   style : 'default',//style参数会替换掉url中的{Style}字符串
   tileMatrixSetID : '2km', //tileMatrixSetID会替换掉{TileMatrixSet}字符串
   format : 'image/png',
   dimensions: {//dimensions里面的参数只要出现在url中全部会被其value替换掉。
       Layer : 'AMSR2_Snow_Water_Equivalent',
       best: 'best'
   },
   clock: map.clock, //clock表示所使用的时钟,直接设置为系统时钟
   times: times, //重点
   maximumLevel : 5
})
map.addLayer(tileLayer)

3.2 动画轨迹

在平台中,提供SampledPositionProperty类 来实现矢量对象的时序控制,达到 模型等点状对象 沿轨迹平滑移动的目的。只需要指定每个时间对应的坐标即可,中间平台自动进行按时间平滑动画移动。

//构造时序轨迹对象
let propertyFJ = getSampledPositionProperty([
    [116.341348, 30.875522, 500],
    [116.341432, 30.871815, 500], 
    [116.341181, 30.85326, 500], 
    [116.345028, 30.870436, 500],
])

//飞机模型
var graphicModel = new mars3d.graphic.ModelEntity({
    position: propertyFJ,
    orientation: new Cesium.VelocityOrientationProperty(propertyFJ),
    style: {
        url: 'http://data.mars3d.cn/gltf/mars/wrj.glb',
        scale: 0.1,
        minimumPixelSize: 20,
    },
})
graphicLayer.addGraphic(graphicModel)


//计算演示的轨迹
function getSampledPositionProperty(points) {
    let property = new Cesium.SampledPositionProperty()

    let start = map.clock.currentTime
    let positions = mars3d.LatLngArray.toCartesians(points)
    for (let i = 0; i < positions.length; i++) {
        let time = Cesium.JulianDate.addSeconds(start, i * 20, new Cesium.JulianDate())
        let position = positions[i]
        property.addSample(time, position) //指定每个时间对应的位置
    }
    return property
}

运行效果

image.png