譯者:i_dovelemon
日期:2016 / 07 / 05
來源:http://gamedevelopment.tutsplus.com/articles/forward-rendering-vs-deferred-rendering--gamedev-12342
主題:fowward rendering, deferred rendering
如果你是一個3D遊戲開發者,那麼當你在探索遊戲引擎的時候,你可能會遇到這兩個名詞:forward rendering和deferred rendering。同時,你也必須在你的遊戲中選擇一種來實作。但是,它們是什麼意思了?它們之間又有什麼不同了?在做選擇的時候,我們又該選擇哪一個了?
圖1 Defered Rendering for many lights
現代圖形渲染管線
在開始之前,我們先來了解下目前現代的渲染管線是什麼樣的。
在以前,由于顯示卡的限制,我們在渲染的時候能夠做的東西少的可憐。我們不能夠改變一個像素的繪制過程,隻有通過傳遞不同的紋理來改變像素,一旦頂點資料到達顯示卡之後,我們就再也沒有機會對它進行額外的修改。但是時代發生了改變,我們現在的渲染管線都是能夠被我們通過程式設計來進行控制的。我們能夠發送一些代碼到顯示卡上,以此來控制一個像素最終的樣子,通過為一個表面添加額外的法線貼圖來實作表面的凹凸感,同時也能夠增加物質表面的反射效果。
這個代碼就是我們常常看到的geometry shader,vertex shader和fragment shader,通過他們我們能夠很容易的控制顯示卡如何渲染我們的像素。
圖2
Forward Rendering
Forward rendering是一種标準的,最常使用到的渲染方式,大部分的遊戲引擎都支援這項功能。你将你的幾何資料送出到顯示卡上去,它經過計算,将結果投影到投影平面,然後拆分成一個個單獨的頂點,這些頂點再經過轉換,裁剪,最終變成一個一個的像素,這個像素最終将被顯示在我們的螢幕上去。
圖3
從上面的圖中可以看到,這個渲染的方式是一種線性的過程,一個階段進行一樣工作,一個階段接着一個階段,直到最後形成一個完整的圖像。
Deferred Rendering
在Deferred rendering中,正如這個名字(延遲渲染)所指出的那樣,渲染的操作被延遲了一會兒,當所有的資料都被處理完成,并且傳遞到圖形管線的最後的時候,我們在最後進行實際的光照計算,然後形成一張新的圖像。
那麼,我們為什麼要這麼做了?
圖4
而Deferred lighting技術能夠通過更多的渲染pass來減小G-buffer的尺寸。
Light Performance
光照是Forward rendering和Deferred Rendering的主要差別。在一個标準的Forward rendering渲染管線中,光照計算需要在每一個頂點或者每一個片段上進行,而且每一個燈光都要進行這麼多的計算。
如果你的場景有100個幾何體,每一個幾何體有1000個頂點,那麼你大概就有100000個多邊形需要進行處理。當然了,現代的圖形卡處理這些資料還是很快的。但是當我們在片段着色器中進行光照計算的時候,并且需要計算的光源又比較多的時候,就會導緻渲染速度飛快的下降。
是以,開發者們盡量在頂點着色器中進行光照計算,進而減少在片段着色器中進行光照計算。在片段着色器中進行的計算,不管這個像素是否在後面會被其他的像素所遮蓋,也不會是否在視口中可見,它們都需要通過片段着色器進行一次渲染操作。比如,你有一個螢幕,它的分辨率大概在1024×768, 那麼你大概要渲染的也就隻有800000個像素而已。在這樣的情況下,我們的圖形卡很容易就需要每幀處理百萬級的片段。但是,大部分的像素實際上最終都沒有顯示在螢幕上,那麼對這些像素進行光照計算完全是浪費的。
如果你有百萬級的片段要進行渲染,那麼對于每一個燈光都需要渲染這麼多的片段,總的就需要渲染很多的片段了。
對于Forward rendering的渲染算法複雜度,大概為O(num_geometry_fragment * num_lights)。你可以看到這個算法複雜度完全依賴與場景的幾何片段以及燈光的數量。
如果在深度測試的過程中,一個片段沒有被丢棄掉,那麼這個像素最終就需要顯示在螢幕上。
現在,很多的引擎在光源的處理上進行優化,比如将多個光源組合起來,或者使用光照貼圖來模拟光照。但是,如果你的場景需要很多的燈光,那麼我們就需要一些更好的處理方法。
Deferred Rendering to the Rescue
延遲渲染是一個非常有趣的方案,能夠通過這個方法來減少渲染對象的數量,減少渲染片段的數量,我們僅僅需要對最終需要在螢幕上顯示的像素進行光照計算,也就是說我們将需要渲染的片段數量降低到整個螢幕的像素數量。
同樣的,延遲渲染的算法複雜度為O(screen_resolution * num_lights)。
從上面那個算法複雜度,你能夠看到這個算法的複雜度和需要渲染的對象數量沒有關系,僅僅和我們的螢幕像素有關系,是以,我們就能夠大大的提高我們需要使用的光源數量。(讀者請注意,這并不表示,你能夠繪制無數的物體,送出batch的消耗依然存在,不過GPU放松了很多)。
The Guts of Deferred Rendering
每一個幾何體都需要被渲染,但是不需要進行光照計算,我們需要多個渲染目标來實作這個算法。一般來說,深度渲染目标,法線渲染目标和顔色渲染目标。有了這些資訊,我們就能夠對每一個燈光,每一個像素進行光照計算。
圖5
圖6
如果,我們知道了一個像素有多遠,它的法線,我們就能夠通過這些知識來為每一個像素計算光照。
Which to Pick?
如果你的場景中有很多動态的光源,那麼你就需要使用延遲渲染。但是,同樣的我們需要知道延遲渲染的一些缺點:
- 這個渲染算法需要我們的顯示卡能夠支援多渲染目标。老式的顯示卡可能不支援這個功能
- 需要更高的顯示卡帶寬。從前面我們知道,需要對多個渲染目标傳遞資訊,也就是說老的顯示卡可能承受不了這麼大的帶寬。
- 你不能夠使用透明的物體。(除非你組合Forward rendering和Deferred rendering算法)
- 沒辦法實作抗鋸齒。好吧,隻有一些引擎可能不支援采樣,你依然能夠通過邊緣檢測,FXAA等算法來實作。
- 隻支援一種材質,除非你使用的是Deferred Rendering算法的一種變體,Deferred Lighting.
- 陰影的産生依然依賴于光源的數量。
如果你沒有那麼多的光源需要處理,并且你希望你的遊戲能夠在較老的硬體上運作起來,那麼你就使用Forward rendering吧。通過Light map來代替場景中的動态光源,依然能夠實作很多看起來非常酷的效果。
Conclusion
我希望我上面的介紹能夠給你帶來一點啟示。你需要仔細的斟酌,選擇最适合你項目的方式來進行渲染。