前向渲染(Forward Rendering)
它的實現最貼合我們的思維邏輯,當我們渲染模型時,只需要關心畫模型然後直接處理光照,讓它自己去做深度測試,最後深度測試過的都顯示在屏幕上。
1、對要渲染的物體進行遍歷渲染出shadowmap
2、再遍歷一遍上面要渲染的物體,根據shadowmap對每一個物體的像素進行光照計算
優點
很明顯,就是簡單,並且可以針對每個物體指定它的材質,因爲每個物體都是獨立渲染的。
缺點
1、由於依賴深度測試,如果物體是亂序的,可能會出現大量的像素光照計算都是浪費的。
2、不能支持光源數量較多的情況。所以我們一般有兩種做法來處理多光源的情況,一種是一遍渲染多個光源,所有光照運算都在一個着色器中進行,因爲一個着色器有指令數量的限制。另一種是多遍渲染多個光源,意思就是每多一盞燈,就多渲染一次模型,所以性能消耗也比較大。
延遲渲染(Deferred Rendering)
它的做法是在第一遍渲染模型的時候,不進行光照計算,直接將位置、法線深度、顏色等存到G-Buffer。很多人第一次接觸G-Buffer這個名詞都是一頭霧水,其實就是創建多張和屏幕一樣大的紋理,然後每張紋理的像素值分別用來存上面提到的這些數據。也就是說一次渲染,需要輸出多張紋理,這跟前向渲染是不同的, 前向渲染只渲染到一張紋理上,這張紋理最終會渲染在屏幕上。而延遲渲染這多張紋理都不是最終結果,可以理解爲只是用幾張貼圖存儲一堆中間數據。
第二遍再根據G-Buffer的數據,進行光照計算,寫入幀緩衝區
優點
處理完G-Buffer之後,其實每盞燈光就可以通過一個Drawcall的消耗去執行光照計算。第一遍處理完的G-Buffer是深度測試過的,不像前向渲染一樣,有那麼多光照計算的浪費。
缺點
1、最終的光照計算方式只能是一種,也就是其他文章提到的只允許一個材質,因爲最終計算的時候只剩下一堆數據,不知道它們分別是誰的,所以只能無差別對待。而前向渲染可以每個模型一種計算方式。
2、不允許使用透明物件,因爲最終G-Buffer只剩一個像素了,無法進行混合。不過可以在第二遍渲染完之後,用前向渲染的方式渲染透明物體。
3、不支持抗鋸齒,意味着不能用MSAA,不過可以用FXAA進行後期處理
4、有些硬件不支持MRT(Multiple Render Targets 多重紋理目標),也就是輸出到多張紋理上實現G-Buffer的功能
5、G-Buffer需要比較大的帶寬,有些硬件沒不具備這個能力
6、由於光照計算本身性能消耗也不低,延遲渲染的光照計算其實等同於在做一次全屏的後處理,後處理其實對手機來說過於昂貴。而如果只有一盞燈的話,其實前向渲染省了這次額外的渲染。所以移動設備上延遲渲染的性能會比前向渲染的性能要差一些
Forward+ Shading
最近刷知乎的時候看到一篇文章結合了前向渲染和延遲渲染的優勢,爲前向渲染無法同時使用多燈光的問題提供瞭解決的方案。https://zhuanlan.zhihu.com/p/85615283
題外話
其實一開始接觸光照模型、渲染路徑、PBR啥的總被一些名詞折騰得很懵逼,這裏簡單提一下,標準光照模型和PBR都屬於光照模型,在前向渲染中主要負責像素着色器裏的光照計算,而延遲渲染則負責第二遍對整個G-Buffer進行光照計算。渲染路徑指的是整個渲染流程,先後幹什麼事,例如前向渲染和延遲渲染可以是渲染路徑裏的一個環節,還可以有其他的,例如渲染UI或者清屏之類的