1. 程式人生 > >讓粒子可以在白色背景顯示 [Blending Shader 實操]

讓粒子可以在白色背景顯示 [Blending Shader 實操]

ext 實的 return .html 現實 操作 ram truct 使用

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 實操]