譯者注:本文翻譯自Cesium官方博文《Graphics Tech in Cesium - Rendering a Frame》,May 14, 2015 by Patrick Cozzi。html
本文經過追溯Cesium的Scene.render,解釋了Cesium 1.9如何使用其WebGL渲染器渲染每一幀。在Scene.render中放置一個斷點,運行一個Cesium應用,而後繼續。git
因爲Cesium專一於可視化地理空間內容,所以使用許多不一樣光源的場景並不常見,所以Cesium使用傳統的前向陰影管線(Forward Rendering)。 Cesium的管道之因此獨特,是由於它使用了多個視錐體來支持巨大的視距,避免形成Z-fighting現象[Cozzi13]。github
譯者注:正向渲染/前向渲染(Forward Rendering)與延遲渲染(Deferred Rendering)相對,延遲渲染多用於多光照的場合。參看《正向渲染和延遲渲染彼此之間有什麼不一樣》。web
Cesium將具備幀生存期的常量存儲在FrameState對象中。在每一幀的開始階段,將使用諸如相機參數和仿真時間之類的值對其進行初始化。 這個FrameState對可用於其餘對象,例如在整個幀週期中生成命令(繪圖調用)的圖元(primitives)。數組
UniformState是FrameState的一部分,具備通用的預先計算的着色器uniform變量。 在每一幀的開始階段,諸如視圖矩陣和太陽光線矢量等uniform變量將會被計算。緩存
Cesium具備經典的動畫/更新/渲染管線,動畫步驟能夠在不與WebGL交互的狀況下移動圖元(primitives,Cesium表示可渲染對象的術語),更改材質屬性,添加/刪除圖元等。 這不是Scene.render的一部分,它可能會在應用程序代碼中,經過在渲染幀以前顯式設置屬性時發生;或者可能會在Cesium中隱式地,經過使用Entity API分配時間變值觸發。app
Scene.render的第一步是更新場景中的全部圖元。
在此步驟中,每一個圖元會框架
建立/更新其WebGL資源。例如,編譯/連接着色器,加載紋理,更新頂點緩衝區等。Cesium永遠不會在Scene.render以外調用WebGL,由於這樣作會增長requestAnimationFrame的耗時,並使其難以與其餘WebGL引擎整合。函數
返回一組DrawCommand對象的列表,這些對象能夠表示成繪圖調用命令,並引用了由圖元建立的WebGL資源。 有些圖元(例如折線或佈告板(billboard)集合)可能會返回單個命令;而其餘的圖元(例如Globe或3D模型),可能會返回數百個命令。 大多數幀將是幾百到幾千個命令的。性能
Globe對象是Cesium的地形和圖像引擎,能夠看做是一個圖元(primitive)。它的更新函數可處理多層級結構的細節和揀選,以及用於加載地形和圖像圖塊的核心外內存管理。
揀選是圖形引擎常見的優化方法,可以快速的消除視野外的對象;以便管道的其他部分沒必要處理這些對象。經過可見性測試的對象就是「潛在可見性集」,並繼續沿管道傳輸。它們多是可見的,由於使用了不精確的保守可見性測試來提升速度。
Cesium經過使用commands的世界空間的boundingVolume(包圍盒)對象,來對單個命令(圖元,例如執行本身揀選操做的Globe,能夠禁用此功能),自動執行視錐和水平剔除[Ring13a,Ring13b]。
傳統的圖形引擎能夠經過檢查每一個命令(command)的可見性測試來找到潛在的可見集。 Cesium的createPotentiallyVisibleSet函數更進一步,將命令動態地分爲多個視錐(一般是三個),它們將全部命令限制在必定的範圍以內,並保持恆定的遠近比以免深度衝突( z-fighting)。每一個視錐體具備相同的視場和寬高比,只有近平面和遠平面的距離不一樣。做爲一種優化,此函數利用時間相干性,而且若是對於該幀的命令仍然合理,則將重用最後計算的視錐。
每一個視錐體都有各自的命令列表,組成視錐體列表後,咱們如今能夠執行命令了——也就是執行WebGL的drawElements/drawArrays的調用。如下會順着追蹤Cesium的executeCommands相關的內容,由於這是Cesium渲染管線的核心。
首先,清除顏色緩衝區。若是使用了與順序無關的透明度(OIT)[McGuire13,Bagnell13]或快速近似抗鋸齒(FXAA),則它們的緩衝區也將被清除(有關更多信息,請參見下文)。
而後,使用整個視錐體(不是單個計算的視錐之一)來渲染一些特殊狀況的圖元:
包含星星的天空盒。 老式的優化方法是先渲染天空盒,而後跳過清除顏色緩衝區的操做。 現在,這實際上會影響性能,由於清除顏色緩衝區有助於最大程度地壓縮GPU(與清除深度相同)。最佳作法是使天空盒最後渲染以利用Early-Z。Cesium首先渲染天空盒,由於它必須這樣作,須要在每一個視錐體以後清除深度(正以下面所描述的那樣)。
天空大氣。來自[ONeil05]的基本大氣。
太陽。若是太陽是可見的,則渲染太陽的佈告板(billboard)。若是還啓用了泛光過濾器,則會剪掉太陽,而後幾個通道將會被渲染:對顏色緩衝區進行降採樣,變亮,模糊(分別在水平和垂直通道中進行),而後進行升採樣並與原始混合。
接下來,從最遠的視錐開始,按照如下步驟執行每一個視錐中的命令:
視錐體特定的uniform狀態量將會被設置。這只是視錐體的近距離和遠距離。
深度緩衝區將會被清空。
首先執行不透明圖元的命令。 執行命令會設置WebGL狀態,例如渲染狀態(深度,混合等),頂點數組,紋理,着色器程序和統一,而後發出繪圖調用。
接下來,執行半透明命令。若是因爲缺乏浮點紋理而不支持OIT,則將命令從頭至尾排序,而後執行。不然,OIT用於提升相交半透明對象的視覺質量,並避免排序的CPU開銷。命令的着色器針對OIT進行了修補(並緩存),若是支持MRT,則經過一次OIT渲染進行渲染,或者做爲後備經過兩次渲染。能夠參閱OIT.executeCommands。
使用多個視錐會致使一些有趣的狀況,例如若是命令重疊多個視錐,則命令能夠執行屢次。詳細信息請參見[Cozzi13]。
至此,每一個視錐體的命令已執行。若是使用OIT,則執行最後的OIT複合通道。若是啓用了FXAA,則會執行全屏通道以進行抗鋸齒。
與平視顯示器(HUD)類似,覆蓋通道的命令最後執行。
在每一個視錐中,保證按圖元返回命令的順序執行命令。例如,Globe從頭至尾對其命令進行排序,以利用GPU Early-Z優化。
因爲性能一般取決於命令的數量,所以許多圖元使用批處理經過將不一樣的對象組合爲一個命令來減小命令的數量。 例如,BillboardCollection在一個頂點緩衝區中存儲儘量多的佈告板,並使用相同的着色器對其進行渲染。
Cesium使用顏色緩衝區實現拾取。每一個可選取的對象都有一個惟一的ID(顏色)。爲了肯定在給定的(x,y)窗口座標中拾取到內容,將幀渲染到屏幕外的幀緩衝區,其中寫入的顏色爲拾取ID。而後,使用WebGL的readPixels讀取顏色,並將其用於返回拾取的對象。
Scene.pick的管道相似於Scene.render,但因爲例如天空盒,大氣層和太陽沒法拾取而得以簡化。
關於一幀中進行的渲染工做,有一些正在進行中還處於計劃階段的提高。
上面描述的Scene.render中的通道在圖形引擎中很常見:OPAQUE,TRANSLUCENT,而後是OVERLAY。 實際上,OPAQUE分爲GLOBE和OPAQUE。 可能會對其進行擴展,以便其順序爲:基本globe,固定在地面上的矢量數據,而後是通常的不透明對象。 參見#2172。
陰影將經過shadow mapping實現。從每一個陰影投射光的角度渲染場景,而且每一個顯示投射對象都有助於深度緩衝區或陰影貼圖,即從燈光角度到每一個對象的距離。而後,在主色通道中,每一個陰影接收對象檢查每一個光源陰影圖中的距離,以查看其片斷是否在陰影內。實際的生產實現很是複雜,須要解決鋸齒僞像,柔和陰影,多個視錐體以及Cesium的核心外地形引擎。 參見#2594。
添加陰影的一個子集增長了對深度紋理的支持,例如,能夠將其用於針對地形進行深度測試的告示板,並根據深度重構世界空間的位置。
添加陰影的另外一部分是從不一樣角度渲染場景的能力。WebVR支持能夠基於此。標準相機和視錐用於揀選和LOD選擇,而後使用兩個偏愛的視錐(每一個眼睛一個)進行渲染。NICTA的VR插件使用相似的方法,可是使用了兩個畫布。
陰影的另外一個擴展是渲染立方體貼圖的能力,即造成一個盒子的六個2D紋理描述了盒子中間某個點周圍的環境。立方體貼圖可用於反射,折射和基於圖像的照明。立方體貼圖通道的使用代價可能會變得昂貴,所以我懷疑這將僅少許用於即時生成。
Scene.render具備一些後期處理效果,這些效果通過硬編碼,例如太陽泛光,FXAA甚至是OIT合成。咱們計劃建立一個通用的後處理框架,將紋理做爲輸入,經過一個或多個後處理階段運行它們,這些通道基本上是在視口對齊的四邊形上運行的片斷着色器,而後輸出一個或多個紋理。例如,這將用驅動後處理框架的數據代替許多硬編碼的太陽泛光,並打開許多新效果,例如景深,SSAO,發光,運動模糊等。 請參閱這些說明。
Cesium會使用老式的GPGPU來進行GPU加速的圖像重投影,在該渲染過程當中,它將渲染一個與屏幕視口對齊的四邊形,以將重投影推向着色器。這能夠經過在幀開始時的計算過程當中使用後處理框架來完成。參見#751。
我和Dan Bagnell編寫了大多數Cesium渲染器。要得到娛樂,請參閱咱們的Cesium Wiki註釋。 當我還在讀高中時,Ed Mackey在90年代就在AGI進行了最初的多視錐體實現。
[Bagnell13] Dan Bagnell. Weighted Blended Order-Independent Transparency. 2013
[Cozzi13] Patrick Cozzi. Using Multiple Frustums for Massive Worlds. In Rendering Massive Virtual Worlds Course. SIGGRAPH 2013.
[McGuire13] McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
[ONeil05] Sean O’Neil. Accurate Atmospheric Scattering. In GPU Gems. Edited by Matt Pharr and Randima Fernando. 2005.
[Ring13a] Kevin Ring. Horizon Culling. 2013.
[Ring13b] Kevin Ring. Computing the horizon occlusion point. 2013.