 	vec4 shadowMoments;
 	FetchShadowMoments(var_Position.xyz, shadowVert, shadowMoments);
 
+	float vertexDistance = shadowVert.z - SHADOW_BIAS;
 	// FIXME
 	#if 0 // defined(r_PCFSamples)
 	shadowMoments = PCF(var_Position.xyz, u_ShadowTexelSize * u_ShadowBlur, r_PCFSamples);

}

#if defined(r_PCFSamples)
vec4 PCF(vec3 I, float filterWidth, float samples)
{
	vec3 forward, right, up;

	forward = normalize(I);
	MakeNormalVectors(forward, right, up);

	vec4 moments = vec4(0.0, 0.0, 0.0, 0.0);

	return penumbra;
}

vec4 PCSS( vec4 I, float vertexDistance, float PCFSamples )
{
	// step 1: find blocker estimate
	const float blockerSamples = 6.0;
	float blockerSearchWidth = u_ShadowTexelSize * u_LightRadius / vertexDistance;
	float blocker = SumBlocker(I, vertexDistance, blockerSearchWidth, blockerSamples);

	// step 2: estimate penumbra using parallel planes approximation
	float penumbra = EstimatePenumbra(vertexDistance, blocker);

	// step 3: compute percentage-closer filter
	vec4 shadowMoments;

	if(penumbra > 0.0 && blocker > -1.0)
	{
		// float maxpen = PCFsamples * (1.0 / u_ShadowTexelSize);
		// if(penumbra > maxpen)
		//	penumbra = maxpen;
		//

		// shadowMoments = PCF(I, penumbra, PCFsamples);
		shadowMoments = PCF(I, u_ShadowTexelSize * u_ShadowBlur * penumbra, PCFsamples);
	}
	else
	{
		shadowMoments = FetchShadowMoments(I);
	}
}
#endif

float ShadowTest( float vertexDistance, vec4 shadowMoments )
{
	float shadow = 1.0;
#if defined( ESM )
	float shadowDistance = shadowMoments.x;

	// standard shadow mapping
	shadow = step( vertexDistance, shadowDistance );
	//shadow = vertexDistance <= shadowDistance ? 1.0 : 0.0;
	// exponential shadow mapping
	// shadow = clamp(exp(r_OverDarkeningFactor * (shadowDistance - log(vertexDistance))), 0.0, 1.0);
	// shadow = clamp(exp(r_OverDarkeningFactor * shadowDistance) * exp(-r_OverDarkeningFactor * vertexDistance), 0.0, 1.0);
	// shadow = smoothstep(0.0, 1.0, shadow);

	#if defined(r_DebugShadowMaps)
	#extension GL_EXT_gpu_shader4 : enable
		gl_FragColor.r = (r_DebugShadowMaps & 1) != 0 ? shadowDistance : 0.0;
		gl_FragColor.g = (r_DebugShadowMaps & 2) != 0 ? -(shadowDistance - vertexDistance) : 0.0;
		gl_FragColor.b = (r_DebugShadowMaps & 4) != 0 ? shadow : 0.0;
		gl_FragColor.a = 1.0;
	#endif
		
#elif defined( VSM )
	#if defined(VSM_CLAMP)
		// convert to [-1, 1] vector space
		shadowMoments = 2.0 * (shadowMoments - 0.5);
	#endif

	shadow = ChebyshevUpperBound(shadowMoments.xy, vertexDistance, VSM_EPSILON);
#elif defined( EVSM )
	vec2 warpedVertexDistances = WarpDepth(vertexDistance);

	// derivative of warping at depth
	vec2 depthScale = VSM_EPSILON * r_EVSMExponents * warpedVertexDistances;
	vec2 minVariance = depthScale * depthScale;

	float posContrib = ChebyshevUpperBound(shadowMoments.xy, warpedVertexDistances.x, minVariance.x);
	float negContrib = ChebyshevUpperBound(shadowMoments.zw, warpedVertexDistances.y, minVariance.y);

	shadow = min(posContrib, negContrib);
	
	#if defined(r_DebugShadowMaps)
	#extension GL_EXT_gpu_shader4 : enable
		gl_FragColor.r = (r_DebugShadowMaps & 1) != 0 ? posContrib : 0.0;
		gl_FragColor.g = (r_DebugShadowMaps & 2) != 0 ? negContrib : 0.0;
		gl_FragColor.b = (r_DebugShadowMaps & 4) != 0 ? shadow : 0.0;
		gl_FragColor.a = 1.0;
	#endif
#endif
	return shadow;
}

/*
Some explanations by Marco Salvi about exponential shadow mapping:
