短篇圖形學——從“打光”開始,聊聊延遲渲染


3樓貓 發佈時間:2024-03-08 11:32:27 作者:Hakumen Language

前言

前幾天看羽毛直播的切片,裡面有一段他提到場景要做得好看需要一個會“打光”的美術,還有彈幕提到用老黃的硬件以後直接配實時全局光照(RTX光追模式)就可以搞定了。
概念上來說這麼理解沒問題,但由於實時渲染畢竟有著諸多限制,而實際的玩家群體的高端硬件普及率沒那麼樂觀,個人覺得還是有必要聊聊遊戲引擎的“打光”是怎麼發展到現在的。
圖形學裡很多概念強行翻譯會丟失其準確性,Deffered Shading(或者Deffered Rendering)中的這個deffered翻譯成延遲就丟失了很多上下文。硬要說的話,這裡的延遲更多的是在一幀內渲染順序上的變化,是一種不同的渲染思路。
這裡面不會展開光照具體的算法,由於上一篇講紋理其實基本也算介紹了前向渲染(Forward Rendering)的基本思路,這裡從前向渲染的光照開始介紹:

1 前向渲染及其光照

前一篇講紋理渲染的文章已經大概介紹過,對一個物體的前向渲染大致可以理解為多邊形幾何處理(矩陣變換)、讀寫深度緩衝和著色幾個步驟。著色往往可以多於一次繪製,我們把一次繪製的調用叫做Draw Call(有些繪製的調用可以批處理,被稱為Batch)。對於著色上次只提到了紋理映射相關的問題,沒有考慮光照。
傳統管線中常見的光源中比較有代表性的有平行光、點光源、聚光燈、區域光源等:
1)平行光 Directional light——用於近似抽象地球上接收太陽光的情況,強度不隨距離衰減,一般被作為主光源
2)點光源 Point light——覆蓋範圍是球體的有限範圍光源
3)聚光燈 Spotlight——覆蓋範圍是錐體聚光燈形式,常用來模擬手電筒
4)區域光源 Area light——光線追蹤中會主要使用的光源形式,在傳統管線中一般只能設置後用於預渲染靜態物的光照貼圖(Bake)
前3者對於傳統渲染管線來說都是實時光源。在前向渲染的著色這一步,如果有多光源的情況,實際上是每個物體逐光源繪製一次,最後一個物體呈現出的是多光源混合的結果。
(圖中是我在Unity中擺的2個平行光加2個點光源的示例,並展示了4個drawcall逐步疊加上去的渲染結果)
在較新的實時渲染管線中,前向渲染的光照這一步也進行了調整,例如在一次繪製調用中帶入一個主光源(MainLight 一般指平行光)和弱幹個補充光源(AdditionalLight)進行計算,增加了單次計算量但減少了drawcall。光照計算還包含逐頂點(Per vertext)逐像素(Per pixel)兩種方式,這裡不展開了。
假設場景有1000個物體,想要設置大大小小100個光源,如果按照一個物體一個光源繪製一次,最多就會有十萬次drawcall——即使能通過距離或者剔除篩掉一些,但是量級不會顯著下降,這對於現有的大部分硬件都是一個遙不可及的數字了。所以對前向渲染來說,根本不是會不會“打光”的問題了,而是不可能大規模使用實時局部燈光。

2 延遲渲染(Deffered Shading)

延遲渲染(或延遲著色)的提出在當時主要就是提升可容納的光源數量的。
假設待渲染的物體都是不透明的,在硬件越來越多的支持幀緩衝(Frame Buffer)後,其中一個想法就是把渲染物體的一些中間結果緩存到幾何緩衝區(G-Buffer),後續對這個中間結果計算光照。這個過程被大概可以拆解為幾何處理階段光照處理階段
幾何處理階段需要緩存的中間結果有以下幾類——顏色、深度、法線(Normals)
(從左到右分別為顏色、深度、法線緩衝)
法線並不是在延遲渲染中才提出的概念,但確實是本系列第一次提到。簡單的理解法線是一個向量,描述了一個點的方向,在進行光照計算時會影響其結果;三角面和頂點有其對應的法線,如果引入法線貼圖(Normal Map)還可以在像素級別來修改其法線,幫助呈現為視覺上更細緻的模型表面。
(圖中a是法線貼圖,c-d是通過法線貼圖來提升細節表現的例子)
渲染的過程中,物體法線及法線貼圖通過空間變換後,每個像素的法線值就被緩存了下來。
在光照處理階段,結合幀緩衝和之前提到的材質和燈光信息,就可以做光照著色了。此時每個光源每種材質(Per material per light )會對依據緩衝區的中間結果進行一次繪製。
(Wiki上的例子中Deffered Shading的渲染結果)
前文提到的1000個物體100個燈光的問題,在延遲渲染的管線下,假設都是統一材質,則最少只需要幾何1000+光照100次繪製就可以實現了。雖然每次渲染比前向渲染需要更多的渲染帶寬和幀緩衝,但至少(進行一些優化後)數量級上在2000年左右已經是可實現的了。
事實上這也是基於物理的渲染(PBR)材質被提出的一個重要原因,因為延遲渲染需要一個參數上有代表性的材質搞定大部分不透明物體渲染的情況——畢竟材質種類太多就會失去延遲渲染的優勢了。
*延遲渲染也是硬件定製化的主機在某個階段畫質顯得大幅領先於PC遊戲的重要原因——既因為可定製化設計的幀緩衝,也因為主機遊戲更關注寫實化渲染,更少引入那些半透明的亮瞎眼粒子特效。
(圖中展示了延遲渲染的一張“秀肌肉”圖)

3 優劣比較

簡單說一下前線渲染和延遲渲染的對比:

1)前向渲染

優點

  • 1.支持半透明渲染
  • 2.支持使用多個光照pass
  • 3.支持逐物體光照計算(延遲渲染是渲染到幀緩衝,再一起計算光照,所以不支持每一個物體用單獨的光照方式計算)

缺點

  • 1.光源數量對計算量影響巨大,太多光源會嚴重拖慢性能
  • 2.訪問深度數據需要額外再渲染一張深度圖,深度圖對最終渲染結果沒有貢獻

延遲渲染

優點

  • 1.大量光照場景的情況下,優勢明顯
  • 2.經過了剔除,只渲染可見像素,節省計算量
  • 3.對後處理支持良好(幀緩衝中有深度、法線等信息)

缺點

  • 1.對多重抗鋸齒MSAA支持不友好(原理上導致的,幀緩衝已經丟失了物體原始的幾何信息,因此無法正確超採樣)
  • 2.透明物體渲染存在問題(透明物體需要按深度著色並混合,和幀緩衝的思路是違背的)
  • 3.佔用更多的顯存和渲染帶寬
  • 4.只能使用同一個光照pass
至於什麼是光照pass,可以簡單理解為一套預定義的光照渲染計算流程,如數據結構定義、預處理、主函數等,這裡不做更多展開了。

4 現代渲染管線

由於光追也已經是“現代”管線了,這裡的現代建議理解成傳統兩種管線的改良版。這部分主要做一個概念上的介紹。
1)延遲光照( Deferred Lighting
延遲光照主要是改進了延遲渲染中光照不夠靈活的問題,並減少緩衝區的佔用,某種意義上可以理解成是嫁接了前向渲染——因此光照處理部分能支持多Pass了,但也會帶來更多drawcall。
2) 分塊渲染(Tile-Based Rendering)
基本思路是把屏幕空間分塊進行並行的延遲渲染(TBDR),以充分利用GPU的特性。這個方案後續也有迭代和發展,產生了改進版PowerVR TBDR
前向渲染也有其對應的Tiled方案,又被稱為Forward Plus(莫名想起某手機的命名方式)。
(圖中是TBDR的一個概念示意圖,tiled是基於屏幕像素範圍的劃分)
3) 群組渲染(Clustered Rendering)
簡單來說就是對空間進行分塊,然後按前向渲染或延遲渲染的管線進行處理,目標也是充分並行計算。(這裡面有一個物體跨多個空間的問題處理,不展開了)
(圖中是ClusterRendering中對攝像機視錐體空間劃分的示意圖)

尾聲

無論是前向渲染還是延遲渲染,作為表現力的補充還需要引入各種基於預渲染或預採樣的光照技術——如光照貼圖(LightMap)光探針(Light Probe)環境反射CubeMapIBL ),以及環境光等,這裡不展開了。無論實時還是烘焙,都可能面對漏光問題,這就是一個需要“打光”的經驗來化解的問題,有興趣的可以自行搜索瞭解下。
另外,傳統管線的中的陰影實現也是一個大課題。其實陰影的渲染伴隨在以上各個管線的過程中,由於篇幅原因這裡沒法展開講。
在光線追蹤管線中,任何光線傳播都會考慮其能量傳遞和損失,這一點帶來的光照算法就完全不同於傳統管線了。這也是光追管線無法和傳統管線拼接使用的其中一個原因。
遊戲開發商即使不開發光追模式,也必須開發傳統管線模式,這是現在單機3D遊戲的無奈現狀(不是高精度畫面更不用考慮光追了);基於相信Nvidia硬件採用的RTX全局光照方案,至少5年內都不會真正到來,即使到了下一個主機世代,中小開發者還是會繼續使用各種改良後的傳統管線作為主要的“現代渲染管線”。
最後是一些相關資料:
中文內容這篇知乎裡寫得比較詳細了,本文也參考了很多
延遲渲染Wiki(包含了延遲光照)
Tiled Rendering
GDC Cluster-Forward-Rendering

© 2022 3樓貓 下載APP 站點地圖 廣告合作:asmrly666@gmail.com