# Exponential Variance Shadow Mapping - implementation

I use a variance shadow mapping with a "standard" light bleeding fix in my graphics engine which is based on deferred rendering.. I have a single shadow map for a directional light beacause a test scene is relatively small. Saving depth looks like this:

float moment1 = gl_FragCoord.z;
float moment2 = moment1 * moment1;
outColor = vec2(moment1, moment2);


Then I perform a separable gaussian blur on that texture.

float Chebyshev(vec2 moments, float mean, float minVariance)
{
if(mean <= moments.x)
{
}
else
{
float variance = moments.y - (moments.x * moments.x);
variance = max(variance, minVariance);
float d = mean - moments.x;
shadow = variance / (variance + (d * d));
float amount = 0.3f;
shadow =  clamp((shadow - amount) / (1.0f - amount), 0.0f, 1.0f); // standard light bleeding fix
}
}

float minVariance = 0.000001f;


I found a interesting technique - Exponential Variance Shadow Mapping which should provides better light bleeding fix. Here is saving depth for that technique:

float positiveExponent = 40.0f;
float negativeExponent = 5.0f
float depth = gl_FragCoord.z;
vec2 exponents = vec2(positiveExponent, negativeExponent);
depth = 2.0f * depth - 1.0f;
float pos = exp(exponents.x * depth);
float neg = -exp(-exponents.y * depth);
vec2 warpDepth = (pos, neg);
outColor = vec4(warpDepth, warpDepth * warpDepth);


How to implement a shadow test for that technique ? Here is my attempt:

float positiveExponent = 40.0f;
float negativeExponent = 5.0f;
vec2 exponents = vec2(positiveExponent, negativeExponent);

vec2 warpDepth(float depth)
{
depth = 2.0f * depth - 1.0f;
float pos = exp(exponents.x * depth);
float neg = -exp(-exponents.y * depth);
vec2 wDepth = vec2(pos, neg);
return wDepth;
}

float Chebyshev(vec2 moments, float mean, float minVariance)
{
if(mean <= moments.x)
{
}
else
{
float variance = moments.y - (moments.x * moments.x);
variance = max(variance, minVariance);
float d = mean - moments.x;
shadow = variance / (variance + (d * d));
}
}

vec2 posMoments = vec2(moments.x, moments.z);
vec2 negMoments = vec2(moments.y, moments.w);
//float minVariance = 0.000001f;
//Edit
vec2 depthScale = 0.0001f * exponents * wDepth;
vec2 minVariance = depthScale * depthScale;
float posResult = Chebyshev(posMoments, wDepth.x, minVariance.x);
float negResult = Chebyshev(negMoments, wDepth.y, minVariance.y);


Unfortunately it doesn't remove light bleeding. Did I do something wrong ? Maybe I should calculate two different minVariance based on the positive and negative exponents ?

Edit1: Calculating minVariance this way:

vec2 depthScale = 0.0001f * exponents * wDepth;
vec2 minVariance = depthScale * depthScale;
float posResult = Chebyshev(posMoments, wDepth.x, minVariance.x);
float negResult = Chebyshev(negMoments, wDepth.y, minVariance.y);


gives better results but light bleeding is still quite visible.

Edit2: Light bleeding: EVSM with minVariance which is calculated as above gives better result than VSM without standard light bleeding fix, but to get the best result I also use standard light bleeding fix with EVSM. A light bleeding fix is performed in Chebyshev function but maybe I should add it after following calculation: shadow = min(posResult, negResult) ?

EVSM causes small artifacts on the illuminated side of the objects so I add some glPolygonOffset when saving EVSM depth.

• Looks like you have a typo here: vec2 warpDepth = (pos, neg) - should be vec2(pos, neg) – Nathan Reed Nov 19 '13 at 1:46
• Thanks, but I immediately fixed that because I got glsl compiler errors. A problem lies somewhere else. – Irbis Nov 19 '13 at 13:06
• I would be glad to see a screenshot, Irbis! – danijar Nov 21 '13 at 7:41