Shader "Custom/SpriteWithGroundClip" { // 带地面裁剪和阴影的Sprite Shader // 当Sprite的世界Y坐标低于地面高度时,会被裁剪掉 // 支持投射阴影(可选) Properties { _MainTex ("Texture", 2D) = "white" {} _GroundHeight ("地面高度 (Y坐标)", Float) = 0.0 [MaterialToggle] _EnableClip ("启用裁剪", Float) = 1.0 _ClipSoftness ("裁剪边缘柔和度", Range(0, 0.5)) = 0.05 // 阴影设置 [MaterialToggle] _CastShadow ("投射阴影", Float) = 1.0 _ShadowOpacity ("阴影透明度", Range(0, 1)) = 0.5 _ShadowOffset ("阴影偏移 (Y方向)", Float) = -0.1 _ShadowColor ("阴影颜色", Color) = (0, 0, 0, 0.5) // 颜色 _Color ("颜色", Color) = (1, 1, 1, 1) } SubShader { Tags { "RenderPipeline" = "UniversalPipeline" "Queue" = "Transparent" "RenderType" = "Transparent" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Cull Off Pass { Name "SpriteWithGroundClip" HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; float4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float4 color : COLOR; float3 worldPos : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float4 _Color; float _GroundHeight; float _EnableClip; float _ClipSoftness; CBUFFER_END TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = TRANSFORM_TEX(input.uv, _MainTex); output.color = input.color; output.worldPos = TransformObjectToWorld(input.positionOS.xyz); return output; } half4 frag(Varyings input) : SV_Target { UNITY_SETUP_INSTANCE_ID(input); // 采样纹理 half4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); half4 color = texColor * input.color * _Color; // 地面裁剪逻辑 if (_EnableClip > 0.5) { float worldY = input.worldPos.y; float distanceToGround = worldY - _GroundHeight; // 如果在地面以下,裁剪掉 if (distanceToGround < 0) { // 使用柔和边缘 float alpha = smoothstep(0, _ClipSoftness, distanceToGround); color.a *= alpha; // 如果Alpha太小,直接丢弃 if (color.a < 0.01) { discard; } } } return color; } ENDHLSL } // 阴影Pass Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } ZWrite On ZTest LEqual Cull Off HLSLPROGRAM #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 worldPos : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float4 _Color; float _GroundHeight; float _EnableClip; float _ClipSoftness; float _CastShadow; float _ShadowOpacity; float _ShadowOffset; float4 _ShadowColor; CBUFFER_END TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); Varyings ShadowPassVertex(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); // URP阴影Pass需要使用特殊的矩阵变换 float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float4 positionCS = TransformWorldToHClip(positionWS); // 应用阴影偏移(向光源方向偏移) #if UNITY_REVERSED_Z positionCS.z -= unity_LightData.z; #else positionCS.z += unity_LightData.z; #endif output.positionCS = positionCS; output.uv = TRANSFORM_TEX(input.uv, _MainTex); output.worldPos = positionWS; return output; } half4 ShadowPassFragment(Varyings input) : SV_Target { UNITY_SETUP_INSTANCE_ID(input); // 如果不投射阴影,直接丢弃 if (_CastShadow < 0.5) { discard; } // 采样纹理获取Alpha half4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); half alpha = texColor.a * _Color.a; // 地面裁剪逻辑(与主Pass相同) if (_EnableClip > 0.5) { float worldY = input.worldPos.y; float distanceToGround = worldY - _GroundHeight; if (distanceToGround < 0) { float clipAlpha = smoothstep(0, _ClipSoftness, distanceToGround); alpha *= clipAlpha; if (alpha < 0.01) { discard; } } } // 如果Alpha太低,不投射阴影 if (alpha < 0.1) { discard; } // 输出阴影(URP阴影格式) return half4(0, 0, 0, alpha * _ShadowOpacity); } ENDHLSL } } FallBack "Sprites/Default" }