[Unity]色のついた影を付ける[URP]

# 結果
## 影が黒色の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462025/d38c7fb6-7364-4cdf-6a5d-e1667634b275.png)


## 影が水色の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462025/fa1764bb-ae54-0cfe-7316-9de459d2143f.png)




二つの画像の影を比較すると，黒色と水色の影をを確認することができます．



# コード

```ReceiveShadowOnly.shader
Shader "Universal Render Pipeline/Simple Lit"
{
    Properties
    {
        // 影の色をここで指定
        _ShadowColor("Shadow Color", Color) = (0, 0, 0, 0)
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" "IgnoreProjector" = "True" "ShaderModel"="4.5"}
        LOD 300

        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }


            HLSLPROGRAM
            #pragma exclude_renderers gles gles3 glcore
            #pragma target 4.5

            // -------------------------------------
            // Material Keywords
            #pragma shader_feature_local _RECEIVE_SHADOWS_OFF

            // -------------------------------------
            // Universal Pipeline keywords
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            //--------------------------------------

            #pragma vertex LitPassVertexSimple
            #pragma fragment LitPassFragmentSimple

            #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            
            struct Attributes
            {
                float4 positionOS    : POSITION;
                float2 texcoord      : TEXCOORD0;
            };

            struct Varyings
            {
                float2 uv                       : TEXCOORD0;
                float3 positionWS               : TEXCOORD2;
                float4 positionCS               : SV_POSITION;
            };
            
            half4 _ShadowColor;


            Varyings LitPassVertexSimple(Attributes input)
            {
                Varyings output = (Varyings)0;

                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                
                output.positionWS.xyz = vertexInput.positionWS;
                output.positionCS = vertexInput.positionCS;

                return output;
            }


            Light MyGetMainLight(float4 shadowCoord)
            {
                Light light = GetMainLight();


                /// RealTimeShadowの計算 ///
                half4 shadowParams = GetMainLightShadowParams();
                half shadowStrength = shadowParams.x;
                ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
                
                half attenuation;
                attenuation = SAMPLE_TEXTURE2D_SHADOW(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture, shadowCoord.xyz);
                attenuation = SampleShadowmapFiltered(TEXTURE2D_SHADOW_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), shadowCoord, shadowSamplingData);;
                attenuation = LerpWhiteTo(attenuation, shadowStrength);
                
                half shadowAttenuation = BEYOND_SHADOW_FAR(shadowCoord) ? 1.0 : attenuation;
                ///
                
                light.shadowAttenuation = shadowAttenuation;
                
                return light;
            }
            
            half4 LitPassFragmentSimple(Varyings input) : SV_Target
            {
                half4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
                
                Light mainLight = MyGetMainLight(shadowCoord);

                half3 white = half3(1, 1, 1);
                half3 finalColor = lerp(_ShadowColor.rgb, white,  mainLight.shadowAttenuation);
                
                return half4(finalColor, 1);
            }
            ENDHLSL
        }
    }
}
```

影を受けとるオブジェクトにこのシェーダーを用いたマテリアルを貼りつけることで，色付影を付けられます．
SimpleLit.shaderを参考にし，必要な部分だけ抽出しました．


# 方法
Unityでは，リアルタイムの影をレンダリングするために[シャドウマッピング](https://docs.unity3d.com/ja/2021.2/Manual/shadow-mapping.html)と呼ばれる技術を使用しています．
影を付けるにはシャドウマップをサンプリングして，ライトがオブジェクトに遮られているかどうかを判別します．


フラグメントシェーダー内では次のように処理をします．

1. ワールド座標からShadowMapをサンプリングする際に使用するshadowCoordを得る
1. メインライト(Directional Light)から，影が付くかどうかを表すshadowAttenuationを求める
1. shadowAttenuationを影が付いているかどうかを表すマスクであると考え，lerpを使って影の部分は影の色，影出ない部分は白色にする



# おわりに
影に模様とか付けてみたいですね

# 参考
SimpleLit.shader内のForward部分のFragmentPassが書かれてあります．
[SimpleLitForwardPass.hlsl](https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitForwardPass.hlsl)

[Lighting.hlsl](https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl)
[Shadow.hlsl](https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl)