天天看點

WebGL之延遲着色

什麼是延遲着色(Deferred Shading)?它是相對于正常使用的正向着色(Forward Shading)而言的,正向着色的工作模式:周遊光源,擷取光照條件,接着周遊物體,擷取物體的幾何資料,最後根據光照和物體幾何資料進行計算。

但是正向着色(Forward Shading)在光源非常多的情況下,對性能的消耗非常大。因為程式要對每一個光源,每一個需要渲染的物體,每一個需要渲染的片段進行疊代!還有片段着色器的輸出會被之後的輸出覆寫,正向渲染會在場景中因多個物體重合在一個像素上浪費大量的片段着色器運作時間。

延遲着色(Deferred Shading),就是為了解決上述問題而生,尤其是需要渲染幾百上千個光源的場景。

本節實作的效果請看:延遲着色 deferred sharding

WebGL之延遲着色

正向着色僞代碼:

延遲着色(Deferred Shading)工作模式就是将計算量大的渲染光照部分 延遲(Defer) 到後期進行處理,是以它包含兩個處理階段(Pass):

第一個 幾何處理階段(Geometry Pass) 是将對象的各種幾何資訊進行渲染并儲存在叫做G緩沖(G-buffer)的紋理中。主要包括位置向量(Position Vector)、顔色向量(Color Vector)、法向量(Normal Vector)。這些儲存在G緩沖中的幾何資訊将會用來做之後的光照計算。

第二個 光照處理階段(Lighting Pass) 是對G緩沖中的幾何資料的每一個片段進行光照計算。光照處理階段不是直接将每個對象從頂點着色器帶到片段着色器,而是對G緩沖中的每個像素進行疊代,從對應的G緩沖紋理擷取輸入變量。

延遲着色僞代碼:

延遲着色(Deferred Shading) 的 G緩沖(G-buffer) 是基于 幀緩沖(frameBuffer) 實作的,涉及到進階應用,幀緩沖 真的是無處不在啊!該demo的幾何處理階段分别對位置(position),法向量(normal),顔色(color) 進行緩存,那麼對應就要建立3個顔色附件,别忘了同時建立用于深度測試用的 深度緩沖(Z-Buffer)。

WebGL 實作多渲染目标需要打開 WEBGL_draw_buffers 這個擴充,但是 WebGL 2.0 直接就能使用的。我這裡為了友善就基于 WebGL 2.0 來實作,多渲染目标調用方式如下:

因為延遲着色器分兩個階段,那麼對應就需要兩對着色器,首先來看幾何處理階段的着色器。

幾何處理階段 頂點着色器(vertex)

幾何處理階段 片段着色器(fragment),這裡的三個輸出變量對應就是幀緩沖中的三個顔色紋理。

接着就是光照處理階段的着色器組了。

光照處理階段 頂點着色器(vertex),這個非常簡單,映射到幀緩沖,也就是個平面貼圖而已。

光照處理階段 片段着色器(fragment),需要從對應的紋理貼圖取出對應的幾何資料。也就是使用 texture 函數結合貼圖和 貼圖坐标(texcoord) 就可以計算出對應的幾何資料,再結合光照資料渲染出最終結果。

最後就是使用 JavaScript 将整個流程串起來,WebGL 的其他技術細節不再詳細介紹了,具體可以看我之前的 WebGL 教程。這裡介紹一下大體的流程:

幾何處理階段:綁定幀緩沖,切換到對應的program,設定各種變量,輸出到幀緩沖;

光照處理階段:切換回正常緩沖,切換到對應的program,設定各種變量,同時将前面幾何處理階段得到的紋理作為輸入變量,輸出渲染結果;

demo 使用了1個平行光源,10個點光源,3個聚光燈實作了類似舞廳五彩斑斓的渲染效果。

延遲着色(Deferred Shading) 在複雜光照條件下有着性能優勢,但它也有缺點:大記憶體開銷。還有在光源不是很多的場景中,延遲渲染并不一定會更快,甚至有時候由于開銷過大還會變得更慢。當然在更複雜的場景中,延遲渲染會變成一個重要的性能優化手段。