NPR中的透明物體bloom
PBR由於要搞線性空間和色調映射,通常會用R16B16G16A16(對Unity而言就是打開Camera上的HDR開關)來直接儲存HDR的顏色值,輝光的blur效果會直接以亮度值為依據,透明物體也能正確blend,不需要特殊處理。
但是NPR卻不能這麼做,因為從一開始光照的部分就不正常,bloom並不是亮度高的地方強烈,而是「想什麼地方強烈就什麼地方強烈」,所以就只能通過在屏幕上標記bloom強度來實現,通常的做法是將bloom的強度直接存在alpha通道上。
fixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex, i.uv); col.a = _Bloom; return col;}
然後在Bloom後處理的DownSample階段,用Alpha作為權重降低這張Sample圖的顏色值
fixed4 fragDownsample ( v2f_tap i ) : SV_Target{ fixed4 color = tex2D (_MainTex, i.uv20); color += tex2D (_MainTex, i.uv21); color += tex2D (_MainTex, i.uv22); color += tex2D (_MainTex, i.uv23); color /= 4; return max(color - THRESHHOLD, 0) * color.a * ONE_MINUS_THRESHHOLD_TIMES_INTENSITY;}
這種做法在處理不透明物體時是沒問題的,因為原本就不使用alpha通道。但是在透明物體部分,alpha和bloom需要佔用同一個輸出通道,Blend時就會產生衝突。
如果是Add疊加模式還可以處理,因為它實際上也不需要使用Alpha通道,只要需要把透明度預乘到顏色值上。
fixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex, i.uv); col.rgb *= col.a; col.a *= _Bloom; return col;}
普通的AlphaBlend就沒辦法了。
如果Bloom值固定為1,那麼可以用普通的透明Shader正常繪製
但如果這部分Bloom值需要可定製,不用MRT,目前唯一的辦法是雙PASS。
PASS 1: Blend SrcAlpha OneMinusSrcAlphaColorMask RGBfixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex, i.uv) * _Color; return col;}PASS 2: Blend SrcAlpha OneMinusSrcAlphaColorMask Afixed4 fragBloom (v2f i) : SV_Target{ fixed alpha = tex2D(_MainTex, i.uv).a; return fixed4(0,0,0,_Bloom * alpha);}
也就是先屏蔽掉Alpha通道繪製正確的顏色混合,然後再補畫Alpha通道,將Bloom值加入。
理論上是可以利用MRT多加張紋理來專門記錄Bloom值,這樣可以迴避掉這個雙Pass,但這就需要考慮設備兼容性了,還有多餘的帶寬成本。考慮到Add,和願意讓Bloom值為1的透明物體數量眾多,使用雙Pass的情況其實也不是那麼多,所以現在的方案其實適用度已經很廣了。
不過上面最後一個Shader其實是錯的,估計不少人都會犯這個錯。
首先要先說明下GPU BLEND的方式:
Blend SrcAlpha OneMinusSrcAlpha
這是典型的Alpha Blend,第一項指的是「要繪製的部分的alpha通道值」,第二項指的是「一減去前面的那個值」。
最終顏色值就是:
要繪製的顏色的rgba * 繪製部分的alpha + 原來屏幕的顏色 *(1 - 繪製部分的alpha)
在這個公式里,雖然顏色值的疊加效果是正常的,但是alpha通道的結果卻搞了一個alpha的平方出來。
如果屏幕原Alpha值是1時,當圖片Alpha為0.5時,結果卻是0.75。而如果屏幕原Alpha值是0的時候(目前的情況),結果是0.25。
總之,這個錯誤的原因是Alpha通道被重複計算了。
最後導致的結果是,同樣的圖片內容,Bloom值都是0.5,如果使用透明Shader,Bloom效果只有非透明的一半。
所以Pass 2的Blend應該換成
Blend One OneMinusSrcAlpha
最終顏色值是:
要繪製的顏色的Bloom + 原來屏幕的Bloom *(1 - 繪製部分的Bloom)
就能避免剛才的問題,結果也能更符合預期。
Bloom部分用的是Unity舊版後處理,BloomOptimized.cs。修改過的Shader見下。
https://pan.baidu.com/s/1uumkosNIDpLasky3tmQjjA推薦閱讀:
※兩個平均年齡十一歲的小男孩,做了兩款遊戲
※換個角度去看棋牌遊戲
※《Exploring in UE4》關於網路同步的理解與思考[概念理解]
※《伏龍記》ea實錄(week6)
※如何讓動作在遊戲中更加流暢(1)