首页 > 编程语言 >CesiumJS 源码杂谈 - 时间与时钟系统

CesiumJS 源码杂谈 - 时间与时钟系统

时间:2023-05-21 13:45:12浏览次数:40  
标签:API JulianDate clock CesiumJS 杂谈 源码 时间 ._ Date

目录


你知道吗?

  • Cesium 是元素 的英文单词,而 铯原子钟 具有世界上最高的计时精度

  • 时间,是时刻间隔的意思,时刻是静态的点;而时间就指有起止时刻的一段范围

  • 很多应用都要有一个时钟,例如 GPS 授时、实时渲染系统,时间可以测量很多事物,万物运动也体现了时间在流逝

1. 时间的“诞生”

首次创建时间是出现在 Scene 的构造函数中:

function Scene (/**/) {
  // ...

  updateFrameNumber(this, 0.0, JulianDate.now());

  // ...
}

function updateFrameNumber(scene, frameNumber, time) {
  const frameState = scene._frameState;
  frameState.frameNumber = frameNumber;
  frameState.time = JulianDate.clone(time, frameState.time);
}

源于此,很多自己应用 CesiumJS 着色器的文章中就用 FrameState 上的 frameNumber 就近似表达了“时间”的概念,因为在 60FPS 的屏幕上,可以通过 frameNumber / 60 粗略获得时间值(秒),但是一旦浏览器的帧速率变化,比如 144 FPS,这个获得的时间就会不准确。

CesiumJS 使用 JulianDate 类来表示整个程序中的时间,它是一种天文时间系统,叫作“儒略”日期,它有两个成员字段,一个是自儒略第一天(公元前 4713 年 1 月 1 日)到现在的天数 dayNumber,另一个是今天已经走过的秒数(零点起算)secondsOfDay

注:我们所说的公历时间,即 GregorianDate(格里日历记法),在 CesiumJS 中也是有的,是作为 JS 原生类 Date 的高精度替代品。

根据上面的 Scene 类构造函数,使用 JulianDate.now 方法,无论什么时候初始化 CesiumJS,获取的时间值永远都是程序运行的那个时刻:

JulianDate.now = function (result) {
  return JulianDate.fromDate(new Date(), result);
}

所以,真正的时间值在帧状态对象 scene._frameStatetime 字段上。

2. 时间的推进

CesiumJS 内部的时间是如何更新的?

CesiumJS 的渲染源头是 CesiumWidget 对象,它每一帧都会运行 CesiumWidget.prototype.render 方法,会让此对象上的时钟 tick 一次(也就是跳一下),返回的时间就作为这一帧的时间,传递给 Scene.prototype.render,进而调用 updateFrameNumber 函数更新累计帧数、时间值:

CesiumWidget.prototype.render = function () {
  if (this._canRender) {
    this._scene.initializeFrame();
    const currentTime = this._clock.tick();
    this._scene.render(currentTime);
  } else {
    this._clock.tick();
  }
}

所以要看时间是如何更新的,就要看 Clock 对象的 tick 方法。

初始化 Clock 时,默认就以当前的 JulianDate 为时钟起点时刻,往后一天为终点时刻。

每当调用 tick 时,会获取当前的时刻 clock.currentTime,然后调用 JulianDate.addSeconds() 方法把时间往前推。 在所有默认条件下,调用的逻辑分支是:

const milliseconds = currentSystemTime - this._lastSystemTime;
currentTime = JulianDate.addSeconds(
  currentTime,
  multiplier * (milliseconds / 1000.0),
  currentTime
);

而这个 currentSystemTime 即时间戳,来自 Performance API(浏览器高精度性能 API)或 Date API,能获取当前的毫秒数。

最后,把计算的 currentTime(类型是 JulianDate)返回给调用者,也就是 CesiumWidget.prototype.render 方法,继续更新一帧。

3. Entity API 与 Property API 的更新动力源

在之前写源码系列的时候,就提过 Entity API 是怎么运作的。

首先,EntityAPI 挂载于 Viewer 上,若无 Viewer 那默认的 Entity 容器就得自己实现一套,很麻烦。

其次,Viewer 拥有 _onTick 事件,它监听了 CesiumWidgetclockonTick 事件,通过 EventHelper 完成:

eventHelper.add(clock.onTick, Viewer.prototype._onTick, this);

往后就是 DataSourceDisplay、CustomDataSource 等内容了,较为复杂,请移步源码解析文章。

引自源码解析文章,以参数化几何的 Entity 为例,它用的是 GeometryVisualizer,当 GeometryVisualizer 调用 fireChangedEvent 函数后,Visualizer 就会拿到最新的 Entity 定义,进而借助 Property API、Updater 等复杂架构更新数据。

总之,若无时钟的 onTick 跳动,也就没有办法根据当前时间去更新 Entity,也就拿不到最新的 Property,更别说动态更新场景中的三维 Entity 了。

4. 简单应用

4.1. 使用原生 JS Date 对象创建 JulianDate

这个最好的说明就是 JulianDate.now 了,在上面第 1 节已经列出源码。当然,也可以自己来搞一个:

const myDate = JulianDate.fromDate(new Date())

4.2. 使用时间字符串(ISO8601标准的时间字符串或 UTC 时间字符串)创建 JulianDate

以北京时间为例:

const myDate = JulianDate.fromIso8601('2023-05-01T13:15:21+08:00')

注意日期和时间之间有一个大写字母 T。我在尾部加上了 +08:00 表示东八区北京时间。

4.3. 为时钟设置起止时间和速率

这个就很简单了:

clock.startTime = JulianDate.fromIso8601('2023-05-01T00:00:00+08:00')
clock.stopTime = JulianDate.fromDate(new Date('2023/05/02 00:00:00')) // Date 会默认使用当前时区,当然你也可以手动 +8,格式按 Date 的文档来就可以

clock.multiplier = 3600 // 3600倍速,一秒过一小时

注意,设置倍数要配合参数 clock.clockStep === ClockStep.SYSTEM_CLOCK_MULTIPLIERClockStep.TICK_DEPENDENT 才有效。

4.4. 调整时钟的循环情况

clock.clockRange = ClockRange.LOOP_STOP

LOOP_STOP 是默认的,到终点不会停止,会继续往前走,但是会重新回到起点时刻,类似于 重播效果

CLAMPED 会在终点时刻停下来,类似于 播完就停在那里

UNBOUNDED 即使超过终点时刻,也不会停下来,类似 直播效果

标签:API,JulianDate,clock,CesiumJS,杂谈,源码,时间,._,Date
From: https://www.cnblogs.com/onsummer/p/17418504.html

相关文章

  • java基于springboot+vue的土特产在线销售平台、特产在线销售商城,附源码+数据库+lw文档
    1、项目介绍考虑到实际生活中在藏区特产销售管理方面的需要以及对该系统认真的分析,将系统权限按管理员和用户这两类涉及用户划分。(1)管理员功能需求管理员登陆后,主要模块包括首页、个人中心、用户管理、特产信息管理、特产分类管理、特产分类管理、特产评分管理、系统管理、订单......
  • 几篇不错的jquery源码总结的文章
    网上看到的几篇写的不错的jquery源码的文章,感觉不错,转载过来,以备温习之用,有时间自己也该看看源码了。 http://www.iteye.com/topic/349020http://www.iteye.com/topic/545971http://www.iteye.com/topic/1126505http://www.iteye.com/topic/1126505http://www.iteye.com/topic/714......
  • 多款前端商城购物网站html模板源码
    1、仿淘宝粉色女性化妆品网上商城模板html源码​编辑切换为居中添加图片注释,不超过140字(可选)​编辑切换为居中添加图片注释,不超过140字(可选)​编辑切换为居中添加图片注释,不超过140字(可选)2、淘宝京东商......
  • React 源码调试 (react版本17.0.2)
    环境准备//create-react-a匹配版本$create-react-app-V5.0.1//node版本$node-Vv16.16.0  1、第一步通过create-react-app快速创建环境,然后运行yarneject释放webpack配置  npxcreate-react-appreact-debugyarneject 2、第二步降级reac......
  • Go源码阅读——github.com/medcl/esm —— v5.go
    esm(AnElasticsearchMigrationTool)——v5.go https://github.com/medcl/esmrelease:8.7.1通过阅读好的源代码,细致思考,理性分析并借鉴优秀实践经验,提高zuoyang的编程水平,所谓"他山之石,可以攻玉" 该是如此吧。 /*Copyright2016Medcl(mATmedcl.net)Licensed......
  • 互联网医院系统源码解析:实现在线问诊、挂号和支付功能
    互联网医院系统为大家的日常看病提供了更加便捷的服务,近期热度极高。本篇文章,小编将从互联网医院系统源码的角度,解析其如何实现在线问诊、挂号和支付功能。一、基本架构1. 前端前端主要由HTML、CSS和JavaScript等技术实现,通过浏览器与用户进行交互。互联网医院系统源码的前端的主......
  • 【源码解读】asp.net core源码启动流程精细解读
    引言core出来至今,已经7年了,我接触也已经4年了,从开始的2.1,2.2,3.1,5,6再到如今的7,一直都有再用,虽然我是一个Winform仔,但是源码一直从3.1到7都有再看,然后在QQ上面也一直比较活跃,之前好几年前一直说给大家解读asp.netcore源码,在之前的博客中,讲的都是比较粗略化的,因为东西太多......
  • springboot基于vue的MOBA类游戏攻略分享平台、游戏资讯分享平台,附源码+数据库+lw文档+
    1、项目介绍任何系统都要遵循系统设计的基本流程,本系统也不例外,同样需要经过市场调研,需求分析,概要设计,详细设计,编码,测试这些步骤,基于java语言设计并实现了MOBA类游戏攻略分享平台。该系统基于B/S即所谓浏览器/服务器模式,应用java技术,选择MySQL作为后台数据库。系统主要包括系统首......
  • Mybatis Plus 源码分析
    ====================================MybatisPlus源码分析入口:com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration#afterPropertiesSetcom.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration#sqlSessionFactorycom.baomidou.mybatisplus.a......
  • 直播源码技术控制直播稳定之消息篇
     在日常生活中,我们上网看直播在各个直播间内通常能看到各种各样的消息,像是用户为主播打赏礼物,直播间聊天区,又或是用户点赞出现的符号信息等,这些消息在让直播间变得多姿多彩同时,也为直播平台运营商面临了一个问题:当消息类型同时发出且数量庞大时,直播间就很可能崩溃,那我们如何解决......