GodZza

导航

让粒子可以在白色背景显示 [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
    }
  }
}

细心的话,在所谓的最终效果图 中发现还存在一些瑕疵,就是有些地方有黑边,这个问题是 图片的原因 解决方法会在下一篇文章介绍【图片去黑底】

 

 

posted on 2017-08-25 15:09  GodZza  阅读(2327)  评论(0编辑  收藏  举报