让粒子可以在白色背景显示 [Blending Shader 实操]

时间:2024-12-15 23:07:19

Unity3D 提供了粒子特效的各种shader,今天要说的是 Additive(因为项目最初就是用了Additive 发生了问题.. ε=ε=ε=┏(゜ロ゜;)┛)

让粒子可以在白色背景显示 [Blending Shader 实操]

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 会"消失"

问题图:

让粒子可以在白色背景显示 [Blending Shader 实操]   让粒子可以在白色背景显示 [Blending Shader 实操]

而 放在暗处便可以看得清楚些(越暗越明显)

让粒子可以在白色背景显示 [Blending Shader 实操]

理想效果图:

让粒子可以在白色背景显示 [Blending Shader 实操]

所以要让Particle 在黑白底上都能现实清楚,所以不能单单使用Additive。

具体方法是 作2次Pass,2次Pass 使用不同的Blend 方式

第一次Pass [Blend SrcAlpha OneMinusSrcAlpha] 
第二次Pass [Blend SrcAlpha one] // Additive

下面这段存粹是根据视角效果调整的参数,不是唯一的方法。

Blend SrcAlpha one Blend SrcAlpha OneMinusSrcAlpha 
让粒子可以在白色背景显示 [Blending Shader 实操]  让粒子可以在白色背景显示 [Blending Shader 实操]

根据上图我们发觉 单纯使用 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
让粒子可以在白色背景显示 [Blending Shader 实操]

哪怕调亮了一点 给人的感觉还是没有光的感觉 这是 Blend 的原因

 让粒子可以在白色背景显示 [Blending Shader 实操]

[最终效果] = 左边的效果 再 加 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 (,,,)
} 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 实操]