【Unity】【シェーダ】CGINCLUDEブロックの使い方

f:id:halya_11:20180203140255p:plain:w300

地味に使ったことなかったのでメモ。

CGINCLUDE?

CGINCLUDEブロックは、複数パス間における共通設定を記述するブロックらしいです。
「設定」ってどこまでだろう。

qiita.com

検証用シェーダを作成

適当に2パスのシェーダを書いてみます。

Shader "Test_CgInclude"
{
    Properties
    {
        _Color ("Color", Color) = (0,0,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

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

            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            half4 _Color;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex + v.normal * 0.1);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }

        Pass
        {
            Blend One One

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

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            half4 _Color;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return 1.0 - _Color;
            }
            ENDCG
        }
    }
}

処理に特に意味はないです。 一応Cubeにアタッチするとこんな感じ。

f:id:halya_11:20180203140255p:plain:w300

変数をCGINCLUDEに

_ColorをCGINCLUDEに移してみます。

Shader "Test_CgInclude"
{
    Properties
    {
        _Color ("Color", Color) = (0,0,0,0)
    }

    SubShader
    {

        Tags { "RenderType"="Opaque" }

        CGINCLUDE
        half4 _Color;
        ENDCG

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

            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex + v.normal * 0.1);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }

        Pass
        {
            Blend One One

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

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return 1.0 - _Color;
            }
            ENDCG
        }
    }
}

問題なく先ほどと同様のレンダリング結果が得られました。
異なるパス間で同じ変数を定義しなくて済むようになったので、CGINCLUDEの効果が得られました。

構造体の定義やキーワードの記述も書ける

変数の宣言以外にも、構造体の定義とか#pragma キーワードとかも移してみました。
問題なさそうです。

Shader "Test_CgInclude"
{
    Properties
    {
        _Color ("Color", Color) = (0,0,0,0)
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGINCLUDE
       #pragma vertex vert
       #pragma fragment frag
        
       #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float4 normal : NORMAL;
        };

        struct v2f
        {
            float4 vertex : SV_POSITION;
        };

        half4 _Color;

        ENDCG

        Pass
        {
            CGPROGRAM

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex + v.normal * 0.1);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }

        Pass
        {
            Blend One One

            CGPROGRAM
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return 1.0 - _Color;
            }
            ENDCG
        }
    }
}

SubShader間でも共有できる

まあこうなってくるとSubShader間でも共通で使えるんでしょうが、一応試してみます。

Shader "Test_CgInclude"
{
    Properties
    {
        _Color ("Color", Color) = (0,0,0,0)
    }

    CGINCLUDE

   #pragma vertex vert
   #pragma fragment frag
    
   #include "UnityCG.cginc"

    struct appdata
    {
        float4 vertex : POSITION;
        float4 normal : NORMAL;
    };

    struct v2f
    {
        float4 vertex : SV_POSITION;
    };

    half4 _Color;

    ENDCG

    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            Blend One One

            CGPROGRAM
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return 1.0 - _Color;
            }
            ENDCG
        }
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex + v.normal * 0.1);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}

エラーにならず、SubShader間でも問題なく共有できました。
ソースコードも結構スッキリしました。

複数パス使うときには積極的に使っていきたいです。