讓粒子可以在白色背景顯示 [Blending Shader 實操]
Unity3D 提供了粒子特效的各種shader,今天要說的是 Additive(因為項目最初就是用了Additive 發生了問題.. ε=ε=ε=┏(゜ロ゜;)┛)
Additive Particle Shader 其Blending 方式是 Blend SrcAlpha one。至於Blend 的操作可以看這篇文章 [轉] SHADER BLENDING,此處不再詳述。
其原理很簡單,其實就是在原圖的基礎上使用加法將顏色進行疊加。[註:Blend SrcAlpha one的方式(Blend 方式具體不詳述)]
其Shader 大概如下:
fixed4 frag(PixelInput I):COLOR { fixed4 c= tex2D (_MainTex, I.uv_MainTex) * I.color; return c; } Pass { Blend SrcAlpha one CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG // 下面使用固定渲染管線的寫法能達到同樣效果 //SetTexture [_MainTex] { combine texture * previous }}
但是單純使用 Additive 的話,會導致 在白色的背景上,Particle 會"消失"
問題圖:
而 放在暗處便可以看得清楚些(越暗越明顯)
理想效果圖:
所以要讓Particle 在黑白底上都能現實清楚,所以不能單單使用Additive。
具體方法是 作2次Pass,2次Pass 使用不同的Blend 方式
第一次Pass [Blend SrcAlpha OneMinusSrcAlpha]
第二次Pass [Blend SrcAlpha one] // Additive
下面這段存粹是根據視角效果調整的參數,不是唯一的方法。
Blend SrcAlpha one | Blend SrcAlpha OneMinusSrcAlpha |
根據上圖我們發覺 單純使用 SrcAlpha one 會有"過曝光"的感覺(在黑暗部分沒問題),而SrcAlpha OneMinusSrcAlpha 的話 給人的感覺是"太實",而且沒有發光的感覺。
在SrcAlpha OneMinusSrcAlpha 中導致太實的原因是透明度太低,而針對沒有發光的感覺,可以適當地將 整體調"亮"一點。
感覺視覺效果調整的算法如下:
fixed4 c = tex2D (_MainTex, I.uv_MainTex) * I.color;
c.rgb+= 0.2; //變白一點
c.a = min(c.a, 0.3); // 透明一點
return c;
Blend SrcAlpha OneMinusSrcAlpha +調整算法 | Blend SrcAlpha OneMinusSrcAlpha +調整算法 + Blend SrcAlpha one |
哪怕調亮了一點 給人的感覺還是沒有光的感覺 這是 Blend 的原因 |
[最終效果] = 左邊的效果 再 加 Pass 一次 Blend SrcAlpha one(Additive) |
需要註意的是,每多一個Pass 其實就是多畫了一遍。可以檢查下 遊戲畫面的三角形數 明顯是相對於單純的 Additive 是多了1倍的三角形,這就是多個Pass導致的,效果和性能需要平衡一下。
下面是Shader 源碼:)
Shader "Custom/MyParticlesAdditive" { Properties { _MainTex ("Particle Texture", 2D) = "white" {} } SubShader { Tags { "QUEUE"="Transparent" "IGNOREPROJECTOR"="true" "RenderType"="Transparent" } BindChannels { Bind "vertex", Vertex Bind "color", Color Bind "texcoord", TexCoord } ZWrite Off Cull Off Fog { Color (0,0,0,0) } CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; struct VertexInput { float4 position:POSITION; fixed2 coord:TEXCOORD0; fixed4 color : COLOR; }; struct PixelInput { float4 position:POSITION; fixed2 uv_MainTex:TEXCOORD; fixed4 color : COLOR; }; PixelInput vert(VertexInput I) { PixelInput O; O.position=mul(UNITY_MATRIX_MVP,I.position); O.uv_MainTex= TRANSFORM_TEX(I.coord,_MainTex); O.color = I.color; return O; } fixed4 frag(PixelInput I):COLOR { fixed4 c = tex2D (_MainTex, I.uv_MainTex) * I.color; return c; } fixed4 grayscale(PixelInput I): COLOR { fixed4 c = tex2D (_MainTex, I.uv_MainTex) * I.color; c.rgb+= 0.2; c.a = min(c.a, 0.3); return c; } ENDCG Pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment grayscale ENDCG } Pass { Blend SrcAlpha one SetTexture [_MainTex] { combine texture * previous } //CGPROGRAM //#pragma vertex vert //#pragma fragment frag //ENDCG } } }
細心的話,在所謂的最終效果圖 中發現還存在一些瑕疵,就是有些地方有黑邊,這個問題是 圖片的原因 解決方法會在下一篇文章介紹【圖片去黑底】
讓粒子可以在白色背景顯示 [Blending Shader 實操]