Aizu-Progressive xr Lab blog

会津大学のVR部であるA-PxLの部員が持ち回りで投稿していくブログです。部員がそれぞれVRに関する出来事やVRにちなんだことについて学んだことを書いていきます。

連絡はサークルTwitterのDMへお願いします。
「面白法人カヤックVR分室」としても活動しています。詳細はこちら

ShurikenのCustomVetexStreamsでパーティクル毎のデータをシェーダーに渡す

こんにちは、学部3年ゲーム部VFX班の森口です。
今日はShurikenの設定項目であるCustomVetexStreamsを使ってシェーダーに値を渡す方法を紹介したいと思います。
目次

初めに

今回の記事は技術評論社さんから出版されているUnityゲームエフェクトマスターガイドを主に参考にしており作成するエフェクトの一部にその本で使われているアセットを用いています。そのあたりの説明は本題とは異なるため省略させていただきますのでご了承ください。 この本は非常に参考になる本ですのでエフェクト制作に興味がある方はぜひ購入してみてください。 Unityゲームエフェクトマスターガイドはこちら www.amazon.co.jp

CustomVertexStreamsとは

CustomVetexStreamsとはUnity5.5から追加された機能で簡単に言うとユーザが定義した各パーティクルが持つデータをシェーダーに渡すことができる機能です。
詳しい機能などは公式リファレンスを参照してください。

docs.unity3d.com

例えばテクスチャをUVスクロールするようなエフェクトを作ろうとしたときにUVスクロールを実装したシェーダーをそのまま適応するとすべてのパーティクルが同じようにスクロールしてしまいあまり見栄えのいいものではなくなってしまいます。

そこでCustomVertexStreamsを使うとパーティクルごとに違う値を割り当て、それぞれが違う動きをしてくれるようになります。

今回はこの機能を使って雷のチャージエフェクトを作成していきたいと思います。

CustomVetexStreamsからデータをシェーダーに送る

では実際に実装していきます。
まずはShurikenのRendererモジュールを見てください。そこにCustomVetexStreamsのチェックボックスがありますのでチェックを入れてください。すると項目が増えたかと思います。

f:id:aizu-vr:20190827171933p:plain
Rendererモジュール
おそらく何も設定していない状態ですと上の画像よりも薄いグレーの中の項目が少ないと思います。その中の項目がシェーダーに送られるデータたちです。上の画像にある項目の中で今回主に使うのはCustom1とCustom2の二つになります。 これらの項目は右下にある「+」をクリックしCustom->Custom1(または2).xyzwをクリックすることで追加できます。
これでデータを送る準備はできたのでシェーダー側にうつってどのように受け取るか見ていきましょう。
まずは頂点シェーダーとフラグメントシェーダーに入力として渡す構造体です。

struct appdata {//頂点シェーダーへの入力
         float4 vertex : POSITION;
         float4 uv : TEXCOORD0;
         fixed4 color : COLOR;
         float4 custom1 : TEXCOORD1;
         fixed4 custom2 : TEXCOORD2;
};

struct v2f {//フラグメントシェーダーへの入力
         float4 vertex : SV_POSITION;
         fixed4 color : COLOR;
         float2 uv : TEXCOORD0;
         float4 custom1 : TEXCOORD1;
         float4 custom2 : TEXCOORD2;
                
};

custom1、custom2という変数に先ほどのものが入る形になります。 今回はCustom1にUVスクロールのスピードとEmissionを、Custom2にパーティクルのベースカラーにかけ合わせる色情報を持たせています。
次に頂点シェーダーとフラグメントシェーダーです

v2f vert(appdata v){
         v2f o;
         o.vertex = UnityObjectToClipPos(v.vertex);
         o.uv = TRANSFORM_TEX(v.uv, _MainTex);
         o.color = v.color;
         o.custom1 = v.custom1;
         o.custom2 = v.custom2;
         return o;
}
            
fixed4 frag(v2f i) : SV_TARGET{
         i.uv.y = i.uv.y+_Time.y*i.custom1.y;
         //y軸方向のUVスクロール
         fixed4 c = tex2D(_MainTex, i.uv)*i.color*i.custom2*i.custom1.w;
         //パーティクルの色にcustom2で指定した色を掛けてEmissionを掛けている
         return c;
}

今回はあらかじめ雷用のテクスチャを作成してから使用しているのでy軸方向のUVスクロールのみですがプロシージャルに作成している場合はx軸方向のスクロールも入れることでさらにいい感じになると思います。
できたシェーダーの全体はこちらです

Shader "Custom/Lightning"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        Blend SrcAlpha OneMinusSrcAlpha
        Cull off
        LOD 100

        Pass{
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma vertex vert 
            #pragma fragment frag 
            #pragma multi_compile_fog
            #include "UnityCG.cginc"

            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0

            

            struct appdata {
                float4 vertex : POSITION;
                float4 uv : TEXCOORD0;
                fixed4 color : COLOR;
                float4 custom1 : TEXCOORD1;
                fixed4 custom2 : TEXCOORD2;
            };

            struct v2f{
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 uv : TEXCOORD0;
                float4 custom1 : TEXCOORD1;
                float4 custom2 : TEXCOORD2;
                
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert(appdata v){
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.color = v.color;
                o.custom1 = v.custom1;
                o.custom2 = v.custom2;
                return o;
            }
            
            fixed4 frag(v2f i) : SV_TARGET{
                i.uv.y = i.uv.y+_Time.y*i.custom1.y;
                fixed4 c = tex2D(_MainTex, i.uv)*i.color*i.custom2*i.custom1.w;
                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Shurikenの設定

次にShurikenのほうの設定を行います。Mainモジュールなどは皆さんの好みに変えてくれればと思います。 ちなみに私はこんな感じに設定してます。

f:id:aizu-vr:20190827175947p:plain
Mainモジュール
f:id:aizu-vr:20190827180331p:plain
Emissionモジュール&ColorOverLifetimeモジュール
特に肝心なのが次の設定項目でRendererモジュールの一つ上にあるCustomDataというモジュールにチェックを入れます。このモジュールに設定した項目が先ほどのCustom1,2に対応しています。なのでここの値を変化させることでパーティクルごとのUVスクロールのスピードを変えたりすることができるわけです。
f:id:aizu-vr:20190827182138p:plain
CustomData モジュール
Custom1はVector形でx~wに値を割り振ってあります。今回はyの値がUVスクロールのy軸方向の速度でwがEmissionの値です(別に割り振りには特に意味はないので自由に割り振ってください)。 今回はスクロールスピードをRandomBetweenTwoCurvesにしているのでかなり速度がばらけるようになっています。 後は先ほど作成したシェーダーから作成したマテリアルを割り当ててRenderModeをMeshにして平面を少しねじったようなメッシュを割り当てて中央のコアを作成すれば完成!

最後のほうが少し雑になってしまいましたが使うメッシュはシンプルな長方形でもきれいに見えます。

最後に

いかがだったでしょうか。まだまだシェーダーは勉強中なので今回テクスチャの作成は事前に行いましたがもう少し勉強してより良いエフェクトを作れるようになりたいです。 今回の記事はここまでにしたいと思います。ご覧いただきありがとうございました。

参考ページ

goisagi-517.hatenablog.com

docs.unity3d.com

会津大学VR部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!