ゴイサギ日記

東京でエンジニアとして頑張って何とか生きてます。。ゆる~く更新していきます

【Unity】Shuriken Particle「Custom Vertex Streams」

今回は Shuriken Particle の Renderer モジュールにある Custom Vertex Streams を試してみます。機能自体はUnity5.5からあるものですが使った事がなかったのでまとめてみました。

はじめに

Custom Vertex Streams を使えばパーティクル粒子1つ1つの状態(速度、回転速度、中心座標、etc...)をシェーダーに送る事ができます。つまり、そのデータを元に独自シェーダーを書けば、標準モジュールでは出来ない表現をすることが可能になるとの事です。
docs.unity3d.com

使ってみる

標準モジュールで生存時間(Color over Lifetime)と移動速度(Color by Speed)によるカラー変更は用意されていますが回転による設定は無いので、今回はパーティクルの回転速度に応じて色を変更するサンプルを作ってみます。以下のような回転速度が速いほど赤色になるサンプルです。
f:id:aki517:20180513225318g:plain

まずはParticleオブジェクトを作成して Rendererモジュール の Custom Vertex Streams にチェックを入れて 「+」から Rotation > RotationSpeed を選択します。
f:id:aki517:20180513224127p:plain

「RotationSpeed (TEXCOORD0.z)」となっているのは 「TEXCOORD0 セマンティクス*1の z に回転速度を渡す」という意味になります。
f:id:aki517:20180513224137p:plain

あと確認しやすくするために「Rotation over Lifetime」を有効にして Random Between Two Constants を選択、値を 0 - 720 で設定しておきます。
f:id:aki517:20180513225449p:plain

次にシェーダーを用意します。

Shader "Custom Vertex Streams/Color by Rotation Speed"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _MaxRotAng ("Max Rotation Angle Per Frame", Float) = 12
        _TarCol ("Target Color", Color) = (1,0,0,1)
    }

    SubShader
    {
        Tags { "RenderType" = "Transparent" "Queue"="Transparent" }
            Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float4 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _MaxRotAng;
            fixed4 _TarCol;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                float rate = clamp((v.uv.z / _MaxRotAng), 0, 1);
                o.color = lerp( fixed4(1,1,1,1), _TarCol, rate );
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return tex2D(_MainTex, i.uv) * i.color;
            }
            ENDCG
        }
    }
}

プロパティに最大回転角度/Frameを設定する MaxRotAng と変更色を設定する TarCol を追加してあります。

_MaxRotAng ("Max Rotation Angle Per Frame", Float) = 12
_TarCol ("Target Color", Color) = (1,0,0,1)

ここで回転角度に応じた色変更を行っています。このシェーダーでは uv が TEXCOORD0 セマンティクスとして扱っているので v.uv.z にパーティクルごとの回転角度/Frameが入ってきます。

float rate = clamp((v.uv.z / _MaxRotAng), 0, 1);
o.color = lerp( fixed4(1,1,1,1), _TarCol, rate );

最後に上記シェーダーを適用したMaterialを対象Particleオブジェクトに設定します。プロパティの Max Rotation Angle Per Frame の値を 12 にしているのは Rotation over Lifetime で最大回転角度(秒)が 720° に設定してあるので 12 = 720° / 60フレーム となるためです。
f:id:aki517:20180513224151p:plain

Custom Data モジュール

更にCustom Vertex Streams を使って Custom Data モジュール で設定したパラメータを頂点データに流し込んでみます。

まずはParticleオブジェクトの Custom Data モジュールを有効にして Custom1 のデータ設定を行います。Mode は Vector, Color があります。今回は Vector を使用してみます。Number of Components は使用する要素数です。今回は1つしか使わないので 1 にして下図のように適当にカーブを設定します。
f:id:aki517:20180515004259p:plain

次に RotationSpeed を設定した時と同様に Renderer モジュール から「+」> Custom > Custom1.x を選択して、項目が「Custom1.x (TEXCOORD0.w)」になるのを確認します。 f:id:aki517:20180515004302p:plain

最後に先程の頂点シェーダに以下の1行を追記します。

o.color.a = v.uv.w; // Custom1.x をα値として使う.

最終出力結果は下図のようにCustom1に設定したカーブの周期でαフェードが適用されます。
f:id:aki517:20180515004315g:plain

まとめ

Custom Vertex Streams と Custom Data モジュールを上手く使えば標準モジュールやビルトインシェーダーでは表現出来ない演出が実現できそうです。

また、Custom1, Custom2のパラメータはスクリプト側から渡す事も出来るのでプレイヤーのステータス情報などを渡してそれに応じた演出なども出来そうです。 docs.unity3d.com