【Cesium 歷史博客】多視錐體優化:使用對數深度緩存

導語

Cesium 的渲染引擎是基於高精度渲染設計的。不過,就算是以米做爲單位的常規遊戲引擎,也會遇到精度問題,例如 z值衝突 和 抖動。html

z值衝突是指兩個三角形接近時,有重疊的像素,可是深度緩存的精度不足以肯定哪個三角形更接近相機,當視圖發生變化時,這些重疊像素會閃爍。瀏覽器

之因此會發生 z值衝突,是由於深度緩存的精度 與 深度的倒數成正比,意味着越靠近截平面的三角形繪製精度越高,越遠則越低。緩存

這裏有一個動圖,顯示了相機在 WGS84 橢球上方約 8000 米觀察的地形發生的 z值衝突:性能

z值衝突的兩種解決方法:使用多視錐體、使用對數深度緩存。優化

在 Cesium 1.45 版本中,Cesium 混合了這兩種技術以替代原來單一的多視錐體技術。翻譯

這麼作的好處顯而易見:設計

  • 更好的性能:減小了 drawcall
  • 更好的視覺效果:能夠在不影響性能的狀況下將近平面儘量移動得近一些

1. 多視錐渲染技術

Cesium 原來的多視錐體實現是使用 3 個視錐體,其分割距離分別是 [1, 1000],[1000, 100w], [100w, 10e] 米。3d

這些視錐體從後到前(相對於相機)的順序進行渲染,而且在每一個視錐體中深度緩存被清除。code

渲染開始時,根據繪製命令(DrawCommands)的包裹範圍(boundingVolume),將繪製命令放置在一個或多個圓錐體中。htm

在兩個視錐邊界的繪製命令則兩邊都會繪製一次,爲了優化這個重複繪製,Cesium 從視點觸發,根據最近和最遠的包裹範圍計算合適的近平面和遠平面距離,以最大程度減小視錐。(這句話翻譯得不太好,專業名稱比較多)。

下圖是珠穆朗瑪峯的近地視圖:

將每一個視錐分別着色後的樣子(第一個視錐是紅色,第二個視錐是綠色,黃色介於第一個和第二個視錐中,這裏看不到第三個視錐):

下圖是同樣的地形場景,只不過把視錐體顯示了出來,第一個視錐(1~1000米)過小了這裏看不到。

在這個場景下,有 137 個 drawcall,第一個視錐有 28 個,第二個視錐有 102 個,第三個視錐有 7 個。重複調用數有 26 個,第一個和第二個視錐之間的重複調用佔 12 個;在全部視錐體中都重複的調用有 7 個。

2. 對數深度緩存

z值衝突的另外一種解決方法是使用對數深度緩存技術。

將對數值輸出到深度緩存,能夠很好分配這些數值。Cesium 更新了頂點和片元着色器以支持對數深度緩存。

關於對數緩存技術,能夠參考三篇博客(在國外國內訪問不了)

對上述的場景使用對數深度緩存,近平面爲 0.1,遠平面爲 1e8,只需一個視錐體,一共 111 個 drawcall。

這麼作不只能夠減小 drawcall,並且默認狀況下,近平面更接近相機,從而能夠近距離查看。

對於多個視錐體,這並不是不可實現,可是可能會有性能問題。只用一個視錐體,使用對數深度緩存,能夠減小將繪製命令分配給每一個視錐體的 CPU 計算量。

視錐上清除命令和全屏掃描命令可能比較少。對數深度緩存消除了視錐邊界處的奇怪問題,對後續開發的新功能(後處理、貼地線)會有幫助。

這是一張拖拉機的輪子,近平面爲 1 米。

當近平面距離爲 0.1 米時,輪胎看起來就比較完整了。

簡而言之,對於只有地形瓦片的視圖,刪除重複的 drawcall 爲 10~30個。對於 3dTiles 或 BIM 模型來講,能減小 20~40 個 drawcall。

在片元着色器中,覆蓋平面很大一部分的三角形的深度信息將被寫入深度緩存,在頂點着色器中計算、插值得來的對數數值可能並非對的。對數深度緩存的典型優化方法是僅修改頂點着色器、僅修改接近相機的三角形的片元着色器兩種。

在片元着色器中寫入片元深度值會致使 GPU 的深度檢測被禁用。而在 Cesium 中是不可能的,由於存在一種狀況:可能存在覆蓋屏幕可是不靠近相機的三角形,例如覆蓋整個陸地的超大多邊形。因此,瀏覽器得支持 EXT_frag_depth 這個 WebGL 擴展,才能在片元着色器中寫入片元深度,才能利用這個功能,不然 Cesium 仍會使用舊的多視錐體技術。

雖然 Cesium 中的大多數視圖僅須要一個單個對數深度的視錐,可是也有例外。一個極端的例子是,在很是遙遠的距離觀察一個很大的三角面。

下例是一個極端狀況,即這裏有兩個超級大平面,和地球切面差很少,它們尺寸是同樣的,可是空間距離上只差 300 米,可是相機到觀察目標的距離有 6400w 米。

對於上面的視圖,能夠預見,幾何圖形在三角面距離比較遠時仍然可見(例如行星)。三角面比較靠近的,則看不到,例如衛星。爲了解決這個問題,Cesium使用了一種混合技術,在多個視錐體中,每一個視錐都使用對數深度緩存。減少 Scene.logarithmicDepthFarToNearRatio 的值,就會增長視錐體的個數,而後減小z值衝突。

*譯者注

簡而言之,配合對數深度緩存技術和原來的多視錐體技術的靈活搭配使用,減小 drawcall,提高性能,提高顯示效果。

相關文章
相關標籤/搜索