目錄
- 0. 前置約定
- 本系列說明
- 1. 開始
- 1.1. CesiumWidget 類是控制場景物件觸發渲染的調度器
- 1.2. Scene 物件
- 2. 三維地球哪來的?
- 3. 本篇總結
0. 前置約定
- 對類的使用,不添加
Cesium命名空間前綴,例如對于Viewer,不會寫Cesium.Viewer,默認使用ESM格式解構匯入類; - JavaScript 代碼使用最簡格式(原始碼除外),不加分號,不用雙引號,少注釋,雙空格縮進
本系列說明
佛系連載,想到什么寫什么,
2022 年,寫原理類的文顯得非常“蠢”,大家都想吃快餐,看效果,法克雞絲老哥的系列博客思路跳躍很快,單步說明之間的資訊量很大,需要消化很長時間才能啃完一篇文章,遂決定另開一個風格,提綱挈領地把主要關鍵邏輯大白話說說 —— 可不是真的“大白話”,還是要有一些功底的,
我寫這個,只是為了從 CesiumJS 的渲染架構中汲取一些營養,希望對自己的程式設計能力有提高,希望能從其它繪圖 API 的角度看看能不能優化和實作,
1. 開始
很多人寫 CesiumJS 程式是從 Viewer 開始的
new Viewer('container') // div id
你若只需要一個最干凈的場景(此場景非 Scene 類),不需要時間條、時間控制器、右上角一堆的按鈕,只需要
new CesiumWidget('container') // div id
CesiumJS 內置了大量的默認值,以至于簡單到你可以只傳遞 DOM 的 id 或本身即可創建場景,
1.1. CesiumWidget 類是控制場景物件觸發渲染的調度器
Scene 類是一個三維空間物件的容器,它在原型鏈上有一個 render 方法,寥寥百行,控制了三維場景中若干物體的更新、渲染,
Scene.prototype.render 方法呼叫一次,只更新并渲染一幀,
眾所周知,WebGL 一般會和 requestAnimationFrame, rAF 這個 API 回圈呼叫渲染函式,而讓 canvas 中場景能連續多幀回圈往復運行的調度者,是 CesiumWidget 類,
CesiumWidget 類有一個使用 Object.defineProperties() 方法定義的 setter:
useDefaultRenderLoop: {
get: function () {
return this._useDefaultRenderLoop;
},
set: function (value) {
if (this._useDefaultRenderLoop !== value) {
this._useDefaultRenderLoop = value;
if (value && !this._renderLoopRunning) {
startRenderLoop(this);
}
}
},
}
在實體化 CesiumWidget 時,它會使用傳入的值,若沒有,則是 true:
this._useDefaultRenderLoop = undefined;
this.useDefaultRenderLoop = defaultValue(
options.useDefaultRenderLoop,
true
);
一旦賦值,就開始了 CesiumJS 的渲染回圈,是一個在 模塊內 的函式 startRenderLoop 負責控制的,
function startRenderLoop(widget) {
// ... 節約篇幅,此處非原始碼,省略大量代碼層級,有興趣自己看原始碼
function render(frameTime) {
// ...
widget.render()
requestAnimationFrame(render)
// ...
}
requestAnimationFrame(render)
}
傳入的 widget 是 CesiumWidget 實體,通過 requestAnimationFrame 的呼叫,則不斷地在呼叫這個函式內的區域函式 render,
render 函式內呼叫 widget 的 render 方法,再往下就是呼叫 widget 所擁有的 scene 的 render 方法了,
1.2. Scene 物件
接上文說,
于全域,CesiumWidget 負責控制 DOM 的變化情況,例如視窗尺寸變化導致 DIV 的變化等,并負責起 渲染回圈 的調度,
于單幀,Scene 類則需要使用自己原型鏈上的 render 方法完成自我狀態、資料物件的更新,以及 Scene.js 模塊內的 render 函式觸發 WebGL 繪制,
Scene 類是一個場景物件容器,其 render 方法負責:
- 生命周期事件(preUpdate、preRender、postUpdate、postRender)回呼觸發;
- 更新幀狀態和幀號
- 更新 Scene 中的 Primitive
- 移交渲染權給模塊內的
render函式觸發 WebGL 繪制
2. 三維地球哪來的?
CesiumJS 的三維地球,實際上分兩大部分:
- 地球橢球體與表面的 GIS 影像服務
- 場景中的三維物體
我說過了,CesiumJS 內置了大量的默認值,包括地球橢球體以及影像服務(默認用的必應瓦片服務,要 token),但是,實際上可以不需要地球橢球體和底圖的:
if (defined(scene.globe)) {
scene.globe.beginFrame(frameState);
}
上述代碼片段是 Scene.js 模塊內的 render 函式的一小段,也就是說,若沒有定義 globe,那就不繪制橢球上的幀,
3. 本篇總結
綜上 1、2 節,我認為 CesiumJS 的渲染回圈,到本文 1.2 小節末尾提及的 Scene.js 模塊內 render 函式的呼叫,觸發 WebGL 繪制,就算一幀的邏輯結束,沒有必要再向下探究 Primitive、DataSource、Globe 等資料物體的更新和渲染,也沒有必要深究 WebGL 在 CesiumJS 中如何調度 —— 那都不是渲染回圈的主要內容,
Scene 原型鏈上的 render 函式并沒有更新橢球體,沒有請求地形四叉樹瓦片,而是等待更重要的 Primitive 等三維物體的更新后,才判斷 globe 是否存在,從而決定要不要畫地球(的皮膚),最終才更新并執行 Command,也就是 scene.updateAndExecuteCommands(passState, backgroundColor); 一句代碼,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/457047.html
標籤:GIS
上一篇:while回圈和if陳述句的問題
