🌈

そろそろShaderをやるパート72 色付きの影を受ける

2022/04/09に公開

そろそろShaderをやります

そろそろShaderをやります。そろそろShaderをやりたいからです。
パート100までダラダラ頑張ります。10年かかってもいいのでやります。
100記事分くらい学べば私レベルの初心者でもまあまあ理解できるかなと思っています。

という感じでやってます。

※初心者がメモレベルで記録するので
 技術記事としてはお力になれないかもしれません。

下準備

下記参考
そろそろShaderをやるパート1 Unite 2017の動画を見る(基礎知識~フラグメントシェーダーで色を変える)

デモ

色付きの影を受けるPlaneを並べてみました。
テクスチャーが反映されているので僅かながらに模様もあります。

Shaderサンプル

Shader "Custom/ColorfulShadow"
{

    Properties
    {
        //ここに書いたものがInspectorに表示される
        _MainColor("MainColor",Color) = (1,1,1,1)
        _ShadowColor("ShadowColor",Color) = (0,0,0,1)
        _ShadowTex("ShadowTexture", 2D) = "white" {}
        _ShadowIntensity ("Shadow Intensity", Range (0, 1)) = 0.6
    }
    SubShader
    {
        CGINCLUDE
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"
        ENDCG

        //メインカラーのパス
        Pass
        {
            CGPROGRAM
            //変数の宣言 Propertiesで定義した名前と一致させる
            half4 _MainColor;

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }

            half4 frag(v2f i) : COLOR
            {
                //RGBAにそれぞれのプロパティを当てはめてみる
                return half4(_MainColor);
            }
            ENDCG
        }

        //影を塗りこむパス
        Pass
        {
            Tags
            {
                "Queue"="geometry"
                "LightMode" = "ForwardBase"
            }
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma multi_compile_fwdbase
            #include "AutoLight.cginc"

            sampler2D _ShadowTex;
            float4 _ShadowTex_ST;
            float4 _ShadowColor;
            float _ShadowIntensity;

            //グローバル変数
            float _ShadowDistance;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 shadow_uv : TEXCOORD0;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float2 shadow_uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 worldNormal:NORMAL;
                float3 worldPos : WORLD_POS;
                SHADOW_COORDS(1)
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                TRANSFER_SHADOW(o);
                //タイリングとオフセットの処理
                o.shadow_uv = TRANSFORM_TEX(v.shadow_uv, _ShadowTex);
                //法線方向のベクトル
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                // カメラとオブジェクトの距離(長さ)を取得
                // _WorldSpaceCameraPos:定義済の値 ワールド座標系のカメラの位置
                float cameraToObjLength = clamp(length(_WorldSpaceCameraPos - i.worldPos), 0, _ShadowDistance);
                //1つ目のライトのベクトルを正規化
                float3 L = normalize(_WorldSpaceLightPos0.xyz);
                //ワールド座標系の法線を正規化
                float3 N = normalize(i.worldNormal);
                //内積の結果が0以上なら1 この値を使って裏側の影は描画しない
                float front = step(0, dot(N, L));
                //影の場合0、それ以外は1
                float attenuation = SHADOW_ATTENUATION(i);
                //影の減衰率
                float fade = 1 - pow(cameraToObjLength / _ShadowDistance, _ShadowDistance);
                //影の色
                float3 shadowColor = tex2D(_ShadowTex, i.shadow_uv) * _ShadowColor;
                //影の場所とそれ以外の場所を塗分け
                float4 finalColor = float4(shadowColor, (1 - attenuation) * _ShadowIntensity * front * fade);
                return finalColor;
            }
            ENDCG
        }
        
        //影を落とす処理を行うPass
        Pass
        {
            Tags
            {
                "LightMode"="ShadowCaster"
            }

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

            struct v2f
            {
                V2F_SHADOW_CASTER;
            };

            v2f vert(appdata_base v)
            {
                v2f o;
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                SHADOW_CASTER_FRAGMENT(i)
            }
            ENDCG
        }
    }
}

ほぼほぼ過去記事の内容です。
【参考リンク】
そろそろShaderをやるパート70 オクルージョン用のShaderを作成する
そろそろShaderをやるパート71 影を受けるオクルージョン用のShader

影の色をテクスチャーのサンプリングカラーと指定カラーを乗算しています。
この手法の影の塗分けは、影を受ける側で個々に設定できるのが利点です。

それぞれ別のマテリアルがアタッチされたPlaneを用意しプロパティーを設定しています。

Discussion