float2 g_fResolution : register(c0); float3 g_vViewPos : register(c2); float g_fSplit : register(c23); float4x4 g_mShadowVP : register(c24); float3 g_vShadowViewPos : register(c28); float3 g_vShadowViewDir : register(c29); float4 g_fShadowMapScalingRes : register(c30); sampler2D shadowMapSampler : register(s0); sampler2D depthSampler : register(s1); sampler2D ditherSampler : register(s2); static float g_fRadius = 6.0f / 64.0f; static float g_fBias = 4.0f / 64.0f; static float g_fDepthBias = 16.0f / 64.0f; static float g_fBiasFalloff = 1.5f / 64.0f; static float g_fSharpness = 640.0f / 64.0f; static float g_fBlurSharpness = 640.0f / 64.0f; static float g_fDepthBlurSharpness = 16.0f / 64.0f; static const float2 s_vShadowDisc[] = { float2(-0.326212f, -0.40581f), float2(-0.840144f, -0.07358f), float2(-0.695914f, 0.457137f), float2(-0.203345f, 0.620716f), float2(0.96234f, -0.194983f), float2(0.473434f, -0.480026f), float2(0.519456f, 0.767022f), float2(0.185461f, -0.893124f), float2(0.507431f, 0.064425f), float2(0.89642f, 0.412458f), float2(-0.32194f, -0.932615f), float2(-0.791559f, -0.59771f) }; float4 ps_main(float2 TexCoord : TEXCOORD0, float3 EyeDir : TEXCOORD1) : COLOR0 { // Compute eye space position float fEyeDepth = tex2D(depthSampler, TexCoord).x; float4 vEyePoint = float4(g_vViewPos + fEyeDepth * EyeDir, 1.0f); // Transform eye point to shadow space float4 vShadowCoord = mul(vEyePoint, g_mShadowVP); vShadowCoord.z = dot(vEyePoint.xyz - g_vShadowViewPos, g_vShadowViewDir); vShadowCoord.xy = vShadowCoord.xy * float2(.5f, -.5f) + vShadowCoord.w * (.5f + .5f / g_fShadowMapScalingRes.zw); // Scale radius float2 fScaledRadius = g_fRadius * g_fShadowMapScalingRes.xy; // Transform to shadow map float2 vShadowCoordProj = vShadowCoord.xy / vShadowCoord.w; // Clip pixels outside shadow map clip( float4(vShadowCoordProj, 1.0f - vShadowCoordProj) - fScaledRadius.xyxy ); // Compute sampling plane float4 vShadowCoordDDX = ddx(vShadowCoord), vShadowCoordDDY = ddy(vShadowCoord); float2 vShadowCoordDeltaDepth = float2( vShadowCoordDDX.y * vShadowCoordDDY.z - vShadowCoordDDY.y * vShadowCoordDDX.z, vShadowCoordDDY.x * vShadowCoordDDX.z - vShadowCoordDDX.x * vShadowCoordDDY.z ) / (vShadowCoordDDY.x * vShadowCoordDDX.y - vShadowCoordDDX.x * vShadowCoordDDY.y); vShadowCoordDeltaDepth = vShadowCoord.w * clamp(vShadowCoordDeltaDepth, -16.f, 16.f); // Compute bias float fAdaption = 1.f / (1.0f + g_fBiasFalloff * fEyeDepth); float fAdaptedBias = g_fBias; // lerp(g_fDepthBias, g_fBias, fAdaption); float fAdaptedBlurSharpness = lerp(g_fDepthBlurSharpness, g_fBlurSharpness, fAdaption); // Apply bias float fReferenceDepth = vShadowCoord.z - fAdaptedBias; // Sample random 2D matrix float4 vRotation = tex2D(ditherSampler, TexCoord * g_fResolution / 32.0f) * 2.0f - 1.0f; float2x2 mRotation = float2x2(vRotation.xy, vRotation.zw); float fShadow = -1.f; float fSampleWeight = 1.f / 6; // Sample for(int i = 0; i < 12; ) { float4 fSampleDepth; // Vectorize occlusion code [unroll] for(int j = 0; j < 4; j++, i++) { // Compute some point around this pixel float2 vSampleOffset = fScaledRadius * mul(s_vShadowDisc[i], mRotation); // Compute depth delta float fSampleDeltaDepth = dot(vSampleOffset * vShadowCoordDeltaDepth, 1.f); // Sample shadow map fSampleDepth[j] = tex2D(shadowMapSampler, vShadowCoordProj + vSampleOffset).x - fSampleDeltaDepth; } // Compare shadow map depth with pixel depth // (fSampleDepth < fReferenceDepth) float4 fOcclusion = saturate(fAdaptedBlurSharpness * (fReferenceDepth - fSampleDepth)); // Sum up samples fShadow += dot(fOcclusion, fSampleWeight); } // Write to intermediate buffer return (1.0f - fShadow); // * float4(g_fSplit == float3(0, 1, 2) || g_fSplit == float3(3, 4, 5), 1.0f); }