##概要
Partcleの寿命の割合によってDissolveエフェクトをかける。
CustomVertexStreamsを使っていい感じにする。
##実装
ParticleSystem設定
CustomVertexStreamsを有効にしてUV2、AgePercentの順で追加する。
パラメーター
###shader
// Copyright (c) 2021 @meta556
// Released under the MIT license
// https://opensource.org/licenses/mit-license.php
Shader "metaaa/particleAgeDissolve"
{
Properties
{
_MainTex("MainTex", 2D) = "white" {}
_MainColor("Color", Color) = (1,1,1,1)
_Mask("DissolveMask", 2D) = "white" {}
_Width("Width", Range(0,1)) = 0.001
[HDR] _Color("Line Color", Color) = (1,1,1,1)
_DissolveStartPer("DissolveStartAgePercent", Range(0,1)) = 0.0
_DissolveEndPer("DissolveEndAgePercent", Range(0,1)) = 1.0
}
SubShader
{
Tags { "RenderType" = "Transparent" "Queue"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
fixed4 color : COLOR;
float4 texcoord1 : TEXCOORD1;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float agePercent : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _Mask;
fixed4 _Color;
fixed4 _MainColor;
fixed _Width;
float _DissolveStartPer;
float _DissolveEndPer;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.agePercent = v.texcoord1.x;
o.color = v.color;
return o;
}
float InverseLerp(float a, float b, float x)
{
return (x - a) / (b - a);
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * _MainColor * i.color;
fixed noise = tex2D(_Mask, i.uv).r;
float dissolve = clamp(i.agePercent, _DissolveStartPer, _DissolveEndPer);
dissolve = InverseLerp(_DissolveStartPer, _DissolveEndPer, dissolve);
dissolve = lerp(- _Width, 1 + _Width, dissolve);
// main
col.a = step(noise, 1 - dissolve );
// line
fixed flg = step(noise, 1 - dissolve + _Width) * step(1 - dissolve , noise);
col = (flg >= 1) ? _Color : col;
return col;
}
ENDCG
}
}
}
Particleの寿命をシェーダーで受け取る
CVSにAgePercent(TEXCOORD1.x)を設定したのでappdataで受け取ってFragmentShaderに渡します。
AgePercentは0~1の値で、生まれた直後は0で死に際に1になります。
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
fixed4 color : COLOR;
float4 texcoord1 : TEXCOORD1;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float agePercent : TEXCOORD1;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.agePercent = v.texcoord1.x;
o.color = v.color;
return o;
}
FragmentShaderでDissolveさせる
DissolveMaskのテクスチャのピクセルのr値と寿命を加工した値を比較してアルファを1か0に設定しています。
Dissolveが始まる寿命と終わる寿命を設定するためにAgePercentをClampしています。
InverseLerp関数はlerp関数の逆で、範囲と値から割合を求めます。
Clampしたものをlerpで使うため、InverseLerpで0~1の範囲にしています。
float InverseLerp(float a, float b, float x)
{
return (x - a) / (b - a);
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * _MainColor * i.color;
fixed noise = tex2D(_Mask, i.uv).r;
float dissolve = clamp(i.agePercent, _DissolveStartPer, _DissolveEndPer);
dissolve = InverseLerp(_DissolveStartPer, _DissolveEndPer, dissolve);
dissolve = lerp(- _Width, 1 + _Width, dissolve);
// main
col.a = step(noise, 1 - dissolve );
// line
fixed flg = step(noise, 1 - dissolve + _Width) * step(1 - dissolve , noise);
col = (flg >= 1) ? _Color : col;
return col;
}