LoginSignup
0
0

More than 3 years have passed since last update.

[Unity] 寿命に応じてディゾルブするParticleSystemのシェーダー

Posted at

はじめに

出来たもの
ageDissolveParticleSample.gif

概要

Partcleの寿命の割合によってDissolveエフェクトをかける。
CustomVertexStreamsを使っていい感じにする。

実装

ParticleSystem設定

CustomVertexStreamsを有効にしてUV2、AgePercentの順で追加する。
cvs.png

パラメーター

params.png

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;
}

Link

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0