目錄
- 1. 時間的“誕生”
- 2. 時間的推進
- 3. Entity API 與 Property API 的更新動力源
- 4. 簡單應用
- 4.1. 使用原生 JS Date 物件創建 JulianDate
- 4.2. 使用時間字串(ISO8601標準的時間字串或 UTC 時間字串)創建 JulianDate
- 4.3. 為時鐘設定起止時間和速率
- 4.4. 調整時鐘的回圈情況
你知道嗎?
-
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._frameState 的 time 欄位上,
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 事件,它監聽了 CesiumWidget 的 clock 的 onTick 事件,通過 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_MULTIPLIER 或 ClockStep.TICK_DEPENDENT 才有效,
4.4. 調整時鐘的回圈情況
clock.clockRange = ClockRange.LOOP_STOP
LOOP_STOP 是默認的,到終點不會停止,會繼續往前走,但是會重新回到起點時刻,類似于 重播效果,
CLAMPED 會在終點時刻停下來,類似于 播完就停在那里,
UNBOUNDED 即使超過終點時刻,也不會停下來,類似 直播效果,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/553013.html
標籤:其他
上一篇:Pytest - pytest 命令(2) - 命令引數及含義
下一篇:返回列表
