float ComputeEVSM( float2 vShadowMapUVs, float fReceiverDepth, float fCascadeIndex ) {
//depth should be 0 to 1 range.
float2 warpedDepth = WarpDepth(fReceiverDepth);
float posDepth = warpedDepth.x;
float negDepth = warpedDepth.y;
float4 occluder = tCascadeShadowMaps.Sample( sShadowLinearClamp, float3( vShadowMapUVs, fCascadeIndex ));
float2 posMoments = occluder.xz;
float2 negMoments = occluder.yw;
// compute derivative of the warping function at depth of pixel and use it to scale min
// variance
float posDepthScale = fESMExponentialMultiplier * posDepth;
float posMinVariance = VSM_MIN_VARIANCE * posDepthScale * posDepthScale;
float negDepthScale = fESMExponentialMultiplier2 * negDepth;
float negMinVariance = VSM_MIN_VARIANCE * negDepthScale * negDepthScale;
//compute two Chebyshev bounds, one for positive and one for negative, and takes the
// minimum
float shadowContrib1= ComputeChebyshevBound(posMoments.x, posMoments.y, posDepth, posMinVariance);
float shadowContrib2= ComputeChebyshevBound(negMoments.x, negMoments.y, negDepth, negMinVariance);
return min(shadowContrib1, shadowContrib2);
}