Shader "Unlit/PlanarShadow" { SubShader { HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #ifdef LOW_SOFT_QUALITY #define OPERATOR_SIZE 10 #elif defined(MEDIUM_SOFT_QUALITY) #define OPERATOR_SIZE 16 #else #define OPERATOR_SIZE 32 #endif struct Varyings { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; TEXTURE2D(_SourceTex); SAMPLER(sampler_SourceTex); TEXTURE2D(_DistanceTex); SAMPLER(sampler_DistanceTex); SAMPLER(sampler_LinearClamp); float4 _PossionOperator[32]; float4 _EdgeMapTexelSize; float4 _SourceTex_TexelSize; float2 _ShadowScreenHDir; float2 _ShadowScreenVDir; float _MinSoft; float _SoftScaleByDistance; Varyings FullScreenVert(uint vertexID: SV_VertexID) { Varyings o; o.vertex = GetFullScreenTriangleVertexPosition(vertexID); o.uv = GetFullScreenTriangleTexCoord(vertexID); return o; } half4 buildSoftEdgeVFrag(Varyings input) : SV_Target { half2 uv = input.uv; half2 uvStep = _EdgeMapTexelSize.xy * _ShadowScreenVDir * 0.6f; UNITY_UNROLL for(int i = 0;i<4;i++) { half dis = SAMPLE_TEXTURE2D(_SourceTex, sampler_SourceTex, uv - i * uvStep).r; if(dis > 0) return dis; } return 0; } half4 buildSoftEdgeHFrag(Varyings input) : SV_Target { half2 uv = input.uv; half2 uvStep = _SourceTex_TexelSize.xy * _ShadowScreenHDir* 0.6f; UNITY_UNROLL for(int i = 0; i < 6; i++) { half dis = SAMPLE_TEXTURE2D(_SourceTex, sampler_SourceTex, uv - i * uvStep).r; half dis2 = SAMPLE_TEXTURE2D(_SourceTex, sampler_SourceTex, uv + i * uvStep).r; if(dis > 0) return dis; if(dis2 > 0) return dis2; } return 0; } half4 CircleVisiualFrag(Varyings input) : SV_Target { half2 uv = input.uv; half blurSize = SAMPLE_TEXTURE2D(_DistanceTex, sampler_DistanceTex, uv).r; half2 uvStep = _SourceTex_TexelSize.xy * (_MinSoft + (1 - _MinSoft) * blurSize) * _SoftScaleByDistance; half col = 0; if(blurSize == 0) return SAMPLE_TEXTURE2D(_SourceTex, sampler_LinearClamp, uv).g; UNITY_UNROLL for(int i = 0; i < OPERATOR_SIZE;i++) { col += SAMPLE_TEXTURE2D(_SourceTex, sampler_LinearClamp, uv + uvStep * _PossionOperator[i].xy).g * _PossionOperator[i].z; } return half4(col.rrr,1); } ENDHLSL Pass { Name "BlurV" HLSLPROGRAM #pragma vertex FullScreenVert #pragma fragment buildSoftEdgeVFrag ENDHLSL } Pass { Name "BlurH" HLSLPROGRAM #pragma vertex FullScreenVert #pragma fragment buildSoftEdgeHFrag ENDHLSL } Pass { Name "CircleVisiual" HLSLPROGRAM #pragma multi_compile _ LOW_SOFT_QUALITY MEDIUM_SOFT_QUALITY #pragma vertex FullScreenVert #pragma fragment CircleVisiualFrag ENDHLSL } Pass { Tags { "LightMode" = "PlanarShadow" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing #pragma enable_d3d11_debug_symbols #pragma shader_feature_local TRANSPARENT_SHADOW_CASTER #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" float4 _PlanarShadowCastPlane; float _PlanarShadowMaxSoftDistance; half4 _PlanarShadowColor; TEXTURE2D(_PlanarShadowMap); SAMPLER(sampler_PlanarShadowMap); void CastVertexToPlane(float3 oriPositionWS, float3 lightDirection, out float3 positionWS, out float shadowSoftScale, float objtY) { float3 planeNor = _PlanarShadowCastPlane.xyz; float w = _PlanarShadowCastPlane.w + objtY; // https://zhuanlan.zhihu.com/p/42781261 float castDistance = (w - dot(oriPositionWS.xyz, planeNor)) / dot(lightDirection, planeNor); positionWS = oriPositionWS.xyz + castDistance * lightDirection; shadowSoftScale = max(0, castDistance / _PlanarShadowMaxSoftDistance); } half3 GetPlanarScreenShadowAttenuation(float2 screenUV) { #ifdef PLANAR_SHADOW half attenutaion = SAMPLE_TEXTURE2D(_PlanarShadowMap, sampler_PlanarShadowMap, screenUV).r; return lerp(1, _PlanarShadowColor, attenutaion); #else return 1; #endif } struct attribute { float4 vertex : POSITION; float2 uv : TEXCOORD; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float softValue : TEXCOORD1; }; sampler2D _MainTexture; v2f vert (attribute v) { v2f o; float4 worldPos = mul(UNITY_MATRIX_M, v.vertex); float3 lightDir = -_MainLightPosition.xyz; float y = UNITY_MATRIX_M[1][3]; float3 castPosWS; float softValue; CastVertexToPlane(worldPos.xyz, lightDir, castPosWS, softValue, y); o.softValue = softValue; o.vertex = mul(UNITY_MATRIX_VP, float4(castPosWS, 1)); o.uv = v.uv; return o; } half4 frag (v2f i) : SV_Target { #ifdef TRANSPARENT_SHADOW_CASTER float4 col = tex2D(_MainTexture, i.uv); #else float4 col = 1; #endif return half4(i.softValue,col.a,0, 0); } ENDHLSL } } }