UE渲染師Dyomin:做次世代手遊,可以用好這項技能

2020虛幻引擎技術開放日上,來自虛幻引擎移動端團隊的負責人Jack Porte和團隊的渲染工程師Dmitriy Dyomin,為大家分享了虛幻引擎4對於移動端的更新內容。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

我們已經分享了Jack Porte的演講內容了,接下來,Dmitriy Dyomin會詳細講述虛幻引擎的影象渲染技術,

尤其是移動端的延遲著色。

以下為演講內容(有節選):

大家好!我是Dmitriy Dyomin,我在Epic Games工作,主要任務是改善渲染效果以及一些移動端的綜合功能。今天我要講的是移動平臺的延遲著色。

延遲著色有前向著色難以比擬的高效優點

我們先來介紹

虛幻引擎移動端渲染的現狀。

在移動平臺上的預設情況下,我們在使用渲染器上會用到一種簡單的前向著色技術,它針對移動端GPU,是經過最佳化後有完整功能的電腦端渲染器,你可以在移動端啟用電腦端渲染器的支援,它就在引擎中“平臺”的“專案設定”裡。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

當然,電腦端渲染器也可以和延遲著色功能一起使用,不過電腦端渲染器對移動端來說難以承受,並且不能妥善利用移動端GPU的架構,保證不了延遲著色功能。

所以今天我要介紹一下我們的新延遲著色功能,它針對移動端GPU進行過最佳化。啟用它的方法是在你的專案中新增r。Mobile。ShadingPath=/到DefaultEngine。ini。

我們來看看延遲著色的優點,以及它在移動端GPU上是如何高效實現的。

首先來了解前向著色。它的優點以及侷限是使用前向著色時,你可以透過單個pass渲染完場景,這對移動端GPU來說非常棒,因為它不需要大量記憶體頻寬。

不過,前向著色目前沒有很好的支援光照貼花的方法,要想完全支援它,就必須具備某種D緩衝區,還需要讓場景具備全深度的預渲染。而延遲著色,可以避免這一缺陷。

延遲著色的工作邏輯是,首先,它將所有物件和畫素材質資料都渲染為多種紋理,這稱為G緩衝區。第二,它渲染光照體積在渲染光照體積時,著色器會從G緩衝區讀取資料,並計算最終畫素顏色。

這樣延遲著色就具備了一個主要優點就是,材質和光照的計算是完全相互獨立的。這意味著我們不需要將光照程式碼包含在材質程式碼中,我們也不需要大部分的陰影變體,那是前向著色才需要的。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

同時也讓過度繪製的效能消耗大幅減少,因為在渲染到G緩衝區時,我們執行的是材質程式碼而並不會執行光照程式碼,只有在結尾的時候我們才會處理光照。我們只會在最後將光照應用於可見的畫素。

延遲著色在移動端的效能演示

現在我們來了解一下為什麼延遲著色在移動端GPU上的操作以及它更好的效能。

移動端GPU大多基於圖塊,這意味著它們會將幀緩衝區分佈到名為圖塊的更小區塊上,然後依次渲染這些圖塊,且只將最終結果儲存到系統記憶體中,所有圖塊的渲染都消耗很小,不會將中間結果存入系統記憶體。這有助於減少記憶體頻寬開銷。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

但在延遲著色時,你必須為每個tile做兩個pass,因此你必須儲存中間資料,也就是G緩衝區,將它存入系統記憶體,然後第二pass會把它取樣為紋理並應用光照,從而計算最終畫素顏色。

在GPU和系統記憶體之間,用這種方法移動G緩衝區資料並不高效,我們想要實現的是在單個pass中實現多pass渲染,並且不將中間資料存入系統記憶體,這樣的話 就在保持單個pass渲染的優點的同時,保持了材質和光照資料的相互獨立。

為此,負責應用光照的著色器,需要設法獲取G緩衝區資料,並將其取樣為紋理。

我用的是Metal、Android Vulkan和Android OpenGL,它們都能做到這點,但它們各自的做法都略有不同。

Vulkan是一種現代化的圖形API,大部分現代安卓裝置都支援它,這是一種非常顯性的API,因為它的介面考慮到了基於圖塊的GPU的執行。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

Vulkan渲染過程被分為多個子pass,這些子pass通常有著各自要執行的任務。不過我們可以將多個子pass融合為一個pass,如果可行的話意味著我們可以用較小的消耗保持G緩衝區,而無需把它移動到系統記憶體,這能節省大量外部記憶體頻寬,這對移動端非常重要。

關於移動端的延遲著色,我們最終會得到三個子pass:第一個是G緩衝區渲染子pass,它會寫入G緩衝區,並填充深度附件;第二個是貼花子pass,我們會向G緩衝區寫入,但深度是隻讀的,不過深度還是可以被獲取;最後的子pass我們只會向場景顏色寫入,並獲取G緩衝區和深度。在這裡將所有光照都處理完後,我們會利用前向著色來渲染半透明。最終,一切大功告成。

強調一下,我們總共有三個子pass,它們都被融合為一個pass。第二個子pass往往是空的,場景裡面並不總是有貼花的,但我們還是要把它做出來。這是為了避免出現兩種不同的渲染pass配置,導致渲染pass配置會被烘培進管線狀態物件。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

Metal的原理與之相似,處理要簡單的多。因為在iOS版的Metal上,你無需在渲染pass中分清具體的子pass,以及它們之間的依賴性。在Metal的著色語言中,你可以宣稱某些附件為某個碎片著色器的輸入。然後,它們就有了G緩衝區資料。利用這個機制,你可以實現程式的混合,也可以實現不同的著色功能。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

我剛才說了Android Vulkan和iOS Metal,但Android OpenGL是怎樣的呢?

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

使用Gl拓展項時,是可以實現高效的延遲著色的,有兩種拓展項可以低消耗地訪問晶片上的畫素資料。

首先是畫素本地儲存,支援它的有Mali GPU以及 ImgTech PowerVR GPU。但Adreno GPU不支援它。

第二個拓展項是著色器幀緩衝區讀取,它擁有其它Adreno的支援,但Mali GPU不完全支援它。在Mali上,你只能用這個幀緩衝區拓展項來讀取單個附件的資料。所以我們必須針對每種GPU做不同的延遲著色支援,我們可以在執行時為著色器打補丁,從而實現這點。這取決於裝置的GPU。

我們已經有了可用的原型,它相容畫素本地儲存以及幀緩衝區拓展項。我們仍在反覆雕琢一些細節,讓它在最新版本中完全發揮作用。

有了延遲著色,我們現在就能支援更高質量的反射,可以混合影響到每個畫素的所有反射捕捉,並正確地與非靜態天空光照反射進行混合。

延遲著色,進一步提升光照渲染質量

現在我們來聊一聊我們做過的一些

光照渲染方面的最佳化。

當我們採用平行光時,就會有FullscreenQuad。FullScreenQuad會計算螢幕上每個畫素的光照,但我們並不需要為每個採用無光照著色模型的畫素應用著色。那麼在我們渲染到G緩衝區,渲染無光照著色模型時,我們能做些什麼呢?

我們可以

寫入到無光照畫素的模板。

在這麼做的時候,應用光照我們可以配置模板測試,還可以過濾掉所有無光照畫素。這是一種很棒的最佳化,尤其對於有室外環境的遊戲來說,它們有天空場景,往往會使用無光照著色模型。天空往往佔據一半左右的螢幕,所以你就可以拋棄一半的畫素。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

另一項最佳化

在渲染體積時,可以被應用在區域性光照渲染上。

例如對於聚光燈光源,我們會試著著色所有在體積內的可見畫素,但我們只需要為那些與光照體積相交的幾何體上的畫素著色就行了。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

在這例子中 可以看到光照體積實際上只照亮了地板上的一些畫素和地板上的盒子。有一種舊演算法,它使用雙pass技術會呼叫未受到光照體積影響的畫素,所以我們就會把每個光照體積渲染兩次。

在第一個pass我們並不寫入到顏色緩衝區,我們只渲染體積的正面。我們在深度測試失敗時更新模板,在第二個pass 我們渲染同樣的體積,但採用光照著色器只渲染背面。

UE渲染師Dyomin:做次世代手遊,可以用好這項技能

我們做反向的深度測試,也只對同時透過深度測試和模板測試的畫素著色。使用這種演算法後,你可以僅計算與光照體積相交的畫素。不過這會增添額外的繪製呼叫,以及各繪製呼叫之間的狀態切換。

但在我們的測試中,這項最佳化在大部分移動端的情況下仍然是有益的。尤其是你的場景中並沒有很多區域性光源的情況,因此在你使用延遲著色時,這項最佳化是預設啟用的。但你可以隨時禁用它,只要使用r。Mobile。UselightStencilCulling即可。

我們依次渲染各個區域性光照,按照其貢獻調整最終場景顏色。但當螢幕上有許多區域性光源時,為每個光源進行繪製呼叫,會消耗大量效能。我覺得這個轉折點大概是個可見繪製呼叫個可見光源,所以如果你使用模板裁剪最佳化的話,就必須呼叫。

你會有個只為了渲染光源的大概繪製呼叫,當存在大量重疊光源時,效能消耗也會很大,因為這要消耗大量GPU算力。不過可以採用的辦法是,將視野分散到各個圖塊並在幀開始時執行一個計算任務,由此生成光源列表。它們會影響每個叢集,在渲染平行光時,我們檢視光源列表,可以將影響到當前畫素的所有區域性光源融為一體。這意味著我們可以在一次繪製呼叫中應用所有區域性光源的光照。

用來裁剪區域性光源的最佳化,在延遲著色時,無法與叢集並用。這種叢集延遲著色是被預設禁用的,所以你只能在需要大量可見光源時才能開啟它。

關於移動端延遲著色的效能表現,我們尚未完全探明。但在更早期的測試中,它在GPU上的速度比前向著色慢了5%。但我們可以使用了一些測量工具來檢視資料。

結果表明,延遲著色在GPU上的計算開銷要少得多,使用的記憶體頻寬也少得多,所以它讀寫的記憶體更少。

我們計劃在《堡壘之夜》移動版上,在某些情況下來啟用它,測試延遲著色。

結語:

相比前向著色,延遲著色可能是更好的選擇。移動端延遲著色是一項新功能,它帶有實驗性質,所以對我們來說,它還有很大改進空間。

首先就是最佳化。我說過,它目前採用位的G緩衝區,我覺得我們可以把它降低到位。目前它只支援預設有光照的著色模型,以及無光照的。所以我們要為它新增更多著色模型,至少要有次表面著色和透明塗層。但要新增這些著色模型,我們就需要在G緩衝區內增加額外的空間,所以我們要讓它們變得更精簡。

有了延遲著色,就能夠有效地渲染光照函式,以及IES光照配置檔案。所以我們也添加了IES光照配置檔案。

還有,目前移動端前向渲染可以適用於聚光燈的動態陰影,但延遲渲染做不到。因此我們也需要新增前向渲染。

我們還可以新增螢幕空間反射,用於抗鋸齒的解決方案我們也要新增,以應付高質量時域抗鋸齒方面的工作。

這就是今天的所有內容了,感謝大家的觀看!