譯者注:本文翻譯自Cesium官方博文《Graphics Tech in Cesium - Rendering a Frame》,May 14, 2015 by Patrick Cozzi。
本文通過追溯Cesium的Scene.render,解釋了Cesium 1.9如何使用其WebGL渲染器渲染每一幀。在Scene.render中放置一個斷點,運行一個Cesium應用,然后繼續。
由於Cesium專注於可視化地理空間內容,因此使用許多不同光源的場景並不常見,因此Cesium使用傳統的前向陰影管線(Forward Rendering)。 Cesium的管道之所以獨特,是因為它使用了多個視錐體來支持巨大的視距,避免造成Z-fighting現象[Cozzi13]。
譯者注:正向渲染/前向渲染(Forward Rendering)與延遲渲染(Deferred Rendering)相對,延遲渲染多用於多光照的場合。參看《正向渲染和延遲渲染彼此之間有什么不同》。
設置
Cesium將具有幀生存期的常量存儲在FrameState對象中。在每一幀的開始階段,將使用諸如相機參數和仿真時間之類的值對其進行初始化。 這個FrameState對可用於其他對象,例如在整個幀周期中生成命令(繪圖調用)的圖元(primitives)。
UniformState是FrameState的一部分,具有通用的預先計算的着色器uniform變量。 在每一幀的開始階段,諸如視圖矩陣和太陽光線矢量等uniform變量將會被計算。
更新
Cesium具有經典的動畫/更新/渲染管線,動畫步驟可以在不與WebGL交互的情況下移動圖元(primitives,Cesium表示可渲染對象的術語),更改材質屬性,添加/刪除圖元等。 這不是Scene.render的一部分,它可能會在應用程序代碼中,通過在渲染幀之前顯式設置屬性時發生;或者可能會在Cesium中隱式地,通過使用Entity API分配時間變值觸發。

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
添加陰影的另一部分是從不同角度渲染場景的能力。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.