車両から出る排気煙
ポストプロセシングの概要

パーティクルシステム - 頂点ストリームとスタンダードシェーダーサポート

自分でシェーダーを作成することに抵抗がない場合は、レンダーモジュール に加えてここで紹介するものも使ってパーティクルシステムを設定し、より広い範囲のデータをカスタムシェーダーに渡せます。

速度、サイズ、中心位置など、多くのビルトインの データストリーム があります。非常に効果的なカスタムシェーダーを作成できる点とは別に、これらのストリームではより多くの普遍的な利点があります。

  • Tangent ストリームを使用して、法線マップを適用したパーティクルをサポートします。
  • You can add the Tangent UV2 and AnimBlend streams to use the Standard Shader on particles.
  • フリップブックのリニアテクスチャブレンディングを簡単に実行するには、UV2 と AnimBlend ストリームを加え、Particles/Anim Alpha Blended シェーダーを設定します (これを設定する方法は後の例を参照)。

また、完全にカスタムの 2 つのパーティクルごとのデータストリーム (ParticleSystemVertexStreams.Custom1ParticleSystemVertexStreams.Custom2 もあります。これらは、スクリプトから取得できます。SetCustomParticleDataGetCustomParticleData をデータ配列といっしょに呼び出して使用します。これを使用する方法は 2 つあります。

  • 独自のデータをパーティクルにアタッチしてスクリプトのカスタム動作を実行します。例えば、「体力」値を各パーティクルに設定します。
  • 2 つのカスタムストリームの 1 つを加えることによってデータをシェーダーに渡します。他のストリームをシェーダに送るのと同様です (ParticleSystemRenderer.EnableVertexStreams を参照)。最初の例で例えると、多分、カスタムの体力属性が、スクリプトベースのゲームロジックを走らせるだけでなく、何らかの視覚効果を与えるようになります。

頂点ストリームを追加するとき、Unity はついくつかの情報を各項目の横に括弧で示し、シェーダーでデータを正しく理解できるようにしています。

括弧内の各項目は頂点シェーダー入力に関連しており、それをシェーダーで指定する必要があります。以下は、それを設定するための正しい入力構造体です。

            struct appdata_t {
                            float4 vertex : POSITION;
                            float3 normal : NORMAL;
                            fixed4 color : COLOR;
                            float4 texcoords : TEXCOORD0;
                            float texcoordBlend : TEXCOORD1;
                        };

UV と UV2 は TEXCOORD0 の異なる部分に渡されます。そのため、両方に対し 1 つの宣言を使用します。シェーダー内でそれぞれにアクセスするには、 xy と zw スウィズルを使用します。これにより、頂点データを効果的にパックできます。

ここにアニメーション化したフリップブックのシェーダーの例があります。ここでは、デフォルトの入力 (Position, Normal, Color, UV) も使いますが、2 つめの UV ストリーム (UV2) とフリップブックのフレーム情報 (AnimBlend) の 2 つの追加ストリームも使用します。

Shader "Particles/Anim Alpha Blended" {
Properties {
    _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
    _MainTex ("Particle Texture", 2D) = "white" {}
    _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
}

Category {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
    Blend SrcAlpha OneMinusSrcAlpha
    ColorMask RGB
    Cull Off Lighting Off ZWrite Off

    SubShader {
        Pass {
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #pragma multi_compile_particles
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed4 _TintColor;
            
            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float4 texcoords : TEXCOORD0;
                float texcoordBlend : TEXCOORD1;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                float2 texcoord2 : TEXCOORD1;
                fixed blend : TEXCOORD2;
                UNITY_FOG_COORDS(3)
                #ifdef SOFTPARTICLES_ON
                float4 projPos : TEXCOORD4;
                #endif
                UNITY_VERTEX_OUTPUT_STEREO
            };
            
            float4 _MainTex_ST;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 
                o.vertex = UnityObjectToClipPos(v.vertex);
                #ifdef SOFTPARTICLES_ON
                o.projPos = ComputeScreenPos (o.vertex);
                COMPUTE_EYEDEPTH(o.projPos.z);
                #endif
                o.color = v.color * _TintColor;
                o.texcoord = TRANSFORM_TEX(v.texcoords.xy,_MainTex);
                o.texcoord2 = TRANSFORM_TEX(v.texcoords.zw,_MainTex);
                o.blend = v.texcoordBlend;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            sampler2D_float _CameraDepthTexture;
            float _InvFade;
            
            fixed4 frag (v2f i) : SV_Target
            {
                #ifdef SOFTPARTICLES_ON
                float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
                float partZ = i.projPos.z;
                float fade = saturate (_InvFade * (sceneZ-partZ));
                i.color.a *= fade;
                #endif
                
                fixed4 colA = tex2D(_MainTex, i.texcoord);
                fixed4 colB = tex2D(_MainTex, i.texcoord2);
                fixed4 col = 2.0f * i.color * lerp(colA, colB, i.blend);
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG 
        }
    }   
}
}


また、このシステムと一緒にサーフェスシェーダーを使用することも可能です。その際、注意しないといけない点がいくつかあります。

  • サーフェス関数への入力構造体は、頂点シェーダへの入力構造体と同じではありません。独自の頂点シェーダー入力構造体を用意する必要があります。下の例の appdata_particles の箇所を参照してください。
  • サーフェイスシェーダーを構築すると、名前が特定のトークンで始まる変数は自動処理されるようになります。最も注目に値するのは uv です。自動処理が問題を引き起こさないようにするには、UV 入力に異なる名前 (例えば “texcoord”) を指定してください。

これは、最初の例と同じ機能を持っていますが、サーフェイスシェーダーです。

Shader "Particles/Anim Alpha Blend Surface" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags {"Queue"="Transparent" "RenderType"="Transparent"}
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite off
        LOD 200
        
        CGPROGRAM
        // 物理ベースの標準ライティングモデルです。すべてのライトタイプに影を作ることができます。
        #pragma surface surf Standard alpha vertex:vert

        // ライティングの見栄えをよりよくするには、シェーダーモデル 3.0 がターゲットです。
        #pragma target 3.0

        sampler2D _MainTex;

         struct appdata_particles {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 color : COLOR;
            float4 texcoords : TEXCOORD0;
            float texcoordBlend : TEXCOORD1;
            };


        struct Input {
            float2 uv_MainTex;
            float2 texcoord1;
            float blend;
            float4 color;
        };


        void vert(inout appdata_particles v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input,o);
            o.uv_MainTex = v.texcoords.xy;
            o.texcoord1 = v.texcoords.zw;
            o.blend = v.texcoordBlend;
            o.color = v.color;
          }


        half _Glossiness;
        half _Metallic;
        fixed4 _Color;


        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 colA = tex2D(_MainTex, IN.uv_MainTex);
            fixed4 colB = tex2D(_MainTex, IN.texcoord1);
            fixed4 c = 2.0f * IN.color * lerp(colA, colB, IN.blend) * _Color;
                 
            o.Albedo = c.rgb;
            // Metallic と Smoothness はスライダー変数から取得します
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}


車両から出る排気煙
ポストプロセシングの概要