4
4

影だけを描画する透明な地面シェーダー

Last updated at Posted at 2023-09-19

2023/09/19 : 初稿
2023/12/14 : 追記
2024/08/20 : シーンの影の色(_SubtractiveShadowColor)を適用。さらにおまけで単純なLitシェーダーを書いてみた
Unity : 2021.3.29f1
URP : 12.1.12
マシン : M1Mac(Metal)

追記

エディタでは問題ないのにビルドするとピンク。なんでだと思ったら・・

間違い : "RenderPipeline"="UniversalRenderPipeline"
正解 : "RenderPipeline"="UniversalPipeline"

え、元からそうだっけ?Unity2022辺りから変わった?

本編

Unity税を考えるとUEへの移行をすべきかもしれない、
というのは置いておきまして。

UnityCG.cgincを使った記事はちらほら見かけるのですが、
URP12以降に対応したのが見つからなかったので書いときます。

こんな感じ?

Shader "Utils/ShadowOnlyGround"
{
    Properties
    {
        _ShadowAlpha("ShadowAlpha", float) = 1
    }

    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "RenderPipeline"="UniversalPipeline" // Unity2021では "RenderPipeline"="UniversalRenderPipeline" だったような
            "Queue"="Geometry+1"
        }

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

            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // make fog work
            #pragma multi_compile_fog
            
            // -------------------------------------
            // Universal Render Pipeline keywords
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
            #pragma multi_compile _ _SHADOWS_SOFT

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
                      
            CBUFFER_START(UnityPerMaterial)
            float _ShadowAlpha;
            CBUFFER_END

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 posWS : TEXCOORD0;
                float fogFactor: TEXCOORD1;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex.xyz);
                o.posWS = TransformObjectToWorld(v.vertex.xyz);
                o.fogFactor = ComputeFogFactor(o.vertex.z);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                float4 shadowCoord = TransformWorldToShadowCoord(i.posWS);
                Light mainLight = GetMainLight(shadowCoord);
                half shadow = mainLight.shadowAttenuation;
                float4 col =  float4(_SubtractiveShadowColor.xyz, (1 - shadow) * _ShadowAlpha);
                col.rgb = MixFog(col.rgb, i.fogFactor);
                return col;
            }
            ENDHLSL
        }

        // Used for rendering shadowmaps
        UsePass "Universal Render Pipeline/Lit/ShadowCaster"
    }
}

おまけ

単純なLitシェーダーを自作してみる実験。Unlitはよくネットに転がってますがLitってなかなかないんですよね。自作するときの足がかりにどうぞ。なお、アンビエントとかはUnity標準のシェーダーとは違いますし、GI、ノーマルマップやエミッションやらは追加してないのでセルフでお願いします。

なお、このままだと_CameraDepthTextureに書き込まれません。_CameraDepthTextureに書き込むためには、DepthNormalsOnlyパスを追加する必要があります。なぜDepthOnlyではないのか謎。

Shader "ProjectMain/Lit"
{
    Properties
    {
        // ベースカラー
        [MainTexture] _BaseMap("Texture", 2D) = "white" {}
        [MainColor] _BaseColor("Color", Color) = (1, 1, 1, 1)

        // アンビエント
        _AmbientColor("Ambient", Color) = (0.1, 0.1, 0.1, 0.1)

        // Photoshopのオーバーレイ
        _EnableOverlay("EnableOverlay", Float) = 0
        _OverlayTex("OverlayTex", 2D) = "black" {}
    }

    SubShader
    {
        Tags {
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
            "Queue"="Geometry"
        }

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

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // 影用
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
            #pragma multi_compile _ _SHADOWS_SOFT

            // 光源計算用
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            //#include "Assets/ProjectMain/Shaders/SkyboxFunctions.hlsl"

            // BaseMap sampler
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);

            // Photoshopのオーバーレイ用sampler
            TEXTURE2D(_OverlayTex);
            SAMPLER(sampler_OverlayTex);

            // for SRP Batcher
            CBUFFER_START(UnityPerMaterial)
                // BaseMap
                float4 _BaseMap_ST;
                half4 _BaseColor;

                // アンビエント
                half4 _AmbientColor;

                // Photoshopのオーバーレイ用
                half _EnableOverlay;
                float4 _OverlayTex_ST;
            CBUFFER_END
            
            // 頂点入力
            struct Attributes
            {
                float4 positionOS   : POSITION;
                float3 normalOS     : NORMAL;
                float4 tangentOS    : TANGENT;
                float2 uv           : TEXCOORD0;
			};

            // 頂点出力
			struct Varyings
			{
				float2 uv           : TEXCOORD0;
				float3 positionWS   : TEXCOORD1;
				float3 normalWS     : TEXCOORD2;
				float2 fogCoord     : TEXCOORD3;
				float4 positionCS   : SV_POSITION;

				UNITY_VERTEX_OUTPUT_STEREO
            };

            // 頂点
            Varyings vert(Attributes input)
            {
                Varyings output = (Varyings)0;
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);  
                output.positionCS = vertexInput.positionCS;
                output.positionWS = vertexInput.positionWS;
                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
                output.fogCoord = float2(ComputeFogFactor(vertexInput.positionCS.z), vertexInput.positionVS.z);
                VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);
                output.normalWS = normalInput.normalWS;
                return output;
			}

            // フラグメント
            half4 frag(Varyings input) : SV_Target
            {
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

                float4 shadowCoords = TransformWorldToShadowCoord(input.positionWS);

                // Diffuseカラー
                half2 uv = input.uv;
                float4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv);

                // Photoshopのオーバーレイ
                if (_EnableOverlay > 0.5) { 
#if !UNITY_COLORSPACE_GAMMA
                    texColor.rgb = LinearToSRGB(texColor.rgb);
                    float4 overlayTex = SAMPLE_TEXTURE2D(_OverlayTex, sampler_OverlayTex, uv);
                    overlayTex.rgb = LinearToSRGB(overlayTex.rgb);
#endif
                    texColor.rgb = texColor.rgb < 0.5 ? 2.0 * texColor.rgb * overlayTex.rgb : 1.0 - 2.0 * (1.0 - texColor.rgb) * (1.0 - overlayTex.rgb);
#if !UNITY_COLORSPACE_GAMMA
                    texColor.rgb = SRGBToLinear(texColor.rgb);
#endif
                }

                // RGBA確定
                half3 baseColor = texColor.rgb * _BaseColor.rgb;
                half alpha = texColor.a * _BaseColor.a;

                // メイン方向光源
                Light mainLight = GetMainLight(shadowCoords);
                float NoL = dot(input.normalWS, mainLight.direction);
                float3 color = baseColor * mainLight.color * mainLight.distanceAttenuation * NoL;

                // 追加光源
                uint pixelLightCount = GetAdditionalLightsCount();
                for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex) {
                    Light light = GetAdditionalLight(lightIndex, input.positionWS);
                    half add_NoL = saturate(dot(input.normalWS, light.direction));
                    color +=  baseColor * light.color * light.distanceAttenuation * add_NoL;
                }

                // 影
                half shadowAmount = MainLightRealtimeShadow(shadowCoords);
                color.xyz = lerp(color.xyz, _SubtractiveShadowColor.xyz, 1 - shadowAmount);

                // アンビエント
                color = max(color, _AmbientColor.rgb);

                // フォグ
				color = MixFog(color, input.fogCoord.x);
                
                // 空に溶ける
                //float4 skyboxColor = CalcSkyboxColor(input.positionWS);
                //float viewZ = abs(input.fogCoord.y);
                //float viewZ01 = viewZ * _ProjectionParams.w;
                //color.rgb = lerp(color.rgb, skyboxColor.rgb, viewZ01);

                // 結果
                return half4(color, alpha);
			}
			ENDHLSL
        }

        // Used for rendering shadowmaps
        UsePass "Universal Render Pipeline/Lit/ShadowCaster"
    }

	FallBack "Hidden/Universal Render Pipeline/FallbackError"
}
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4