float chebyshevUpperBound() { vec2 moments = texture2D(ShadowMap,ShadowCoordPostW.xy).rg; // Surface is fully lit. as the current fragment is before the light occluder if (ShadowCoordPostW.z <= moments.x) return 1.0 ; // The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check // How likely this pixel is to be lit (p_max) float variance = moments.y - (moments.x*moments.x); variance = max(variance,0.1); float d = ShadowCoordPostW.z - moments.x; float p_max = (variance / (variance + d*d)); return max(p_max, 0.4); } //Color computation in main() shadow = chebyshevUpperBound(); fragColor = ((ambient_color + diffuse_color * diffuse_value))*texel; fragColor.rgb *= shadow;