最近渲染器終於穩定下來了, 效果也做得差不多了, 於是做一下總結
當初為了追求進度和效果, 直接就是採用最暴力的A16R16G16B16F x 3的G-Buffer:
| COLOR0 |
Normal.x |
Normal.y |
Normal.z |
Depth |
| COLOR1 |
Diffuse.r |
Diffuse.g |
Diffuse.b |
|
| COLOR2 |
Specular.r |
Specular.g |
Specularb |
Specular Glossy |
可以說沒有什麼特殊的, 效果是出來了, 效能很是問題
所以想投入實際使用還是要最佳化一下效能, 對G-Buffer減肥
最苦逼的是渲染風格改了, 材質資訊又增加了Emissive(4分量)和Half-Lambert(3個參數)
RTT的格式當然還是選擇最快的A8R8G8B8, 但是8bit的通道只能儲存[0, 1]範圍的值, 精度只有256級
Normal可以只儲存兩個分量, 參考http://aras-p.info/texts/CompactNormalStorage.html, 用的method#1
雖然理論上有偏差, 但效果可以接受, 我要的是效率
Depth 8bit肯定不行, 之前想過用兩個8bit通道儲存, 實敗了, 解出的值不是連續的, 所以把其中一個RTT的格式改成了R16G16F(又少了一個通道的說...)
MRT並不強制格式一樣, 只要位元一樣就好了(當然還有Hardware的INTZ什麼, 考慮到相容性還沒試http://aras-p.info/texts/D3D9GPUHacks.html#depth)
其中用了一個技巧做position的重建:http://blog.csdn.net/xoyojank/article/details/5294575
為這個把光照計算全部轉移到ViewSpace去計算, 節省了幾條GPU指令
Diffuse沒法省
Specular犧牲掉了顏色, 只保留強度和範圍, 需要兩個參數, 縮放到[0,1]的範圍寫入兩個8bit通道
Half-Lambert光照的結果就是一個定址1D紋理的UV.x(float), 是不是有這個效果需要一個bool(寫入符號, 如+代表有, -代表沒有)
Emissive犧牲掉顏色, 採用Diffuse的顏色, 強度也壓縮一下寫一個8bit通道
Rimlight計算在寫入G-Buffer之前併入Diffuse, 這樣理論上既有錯誤也有損失, 但是效果也是可以接受的, 畢竟是個輔助效果
最後G-Buffer被我搞成了這個樣子:
| COLOR0 |
Depth |
[+/-][Lambert.u] |
| COLOR1 |
Diffuse.r |
Diffuse.g |
Diffuse.b |
Emissive |
| COLOR2 |
Normal.x |
Normal.z |
Specular |
Specular Glossy |
嗯, 要是再加材質資訊, 那我就哭了, 實在沒地方存了.....
另外, 最後合成的輸出範圍最好是HDR(A16R16G16B16F)的, 要不然PostProcess效果出不來
或者使用RGBM(A8R8G8B8)進行壓縮, 然後半透明的元素只能單獨再用一個BlendBuffer(1/4大小)畫完了進行合成, 這樣又可以省掉很多頻寬和填充率
再就是折射可以直接從G-Buffer裡取Diffuse, 不需要再做一個折射用的Pass, 根據Depth進行剪裁
Fog/ShadowMap/SSAO/SoftParticle也可以直接使用G-Buffer中的Depth資訊重建position進行計算
題外話: 延遲渲染的材質靈活性還是差啊, 但是對於程式來說還是挺省事的