Mapeo de Sombra de Varianza Exponencial – implementación

Utilizo un mapeo de sombras de varianza con una corrección de sangrado ligero "estándar" en mi motor de charts que se basa en la representación diferida. Tengo un solo map de sombras para una luz direccional porque una escena de testing es relativamente pequeña. La profundidad de guardado se ve así:

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

Luego realizo un desenfoque gaussiano separable en esa textura.

Prueba de las sombras:

 float Chebyshev(vec2 moments, float mean, float minVariance) { float shadow = 1.0f; if(mean <= moments.x) { shadow = 1.0f; return shadow; } 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 return shadow; } } vec4 shadowCoord = shadowMatrix * vec4(viewSpacePosition, 1.0f); vec2 moments = texture(ShadowMap, shadowCoord.xy).xy; float minVariance = 0.000001f; float shadow = Chebyshev(moments, shadowCoord.z, minVariance); 

Encontré una técnica interesante: Mapeo de sombra exponencial que proporciona una mejor corrección de la luz. Aquí está guardando profundidad para esa técnica:

 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); 

¿Cómo implementar una testing de sombra para esa técnica? Aquí está mi bash:

 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) { float shadow = 1.0f; if(mean <= moments.x) { shadow = 1.0f; return shadow; } else { float variance = moments.y - (moments.x * moments.x); variance = max(variance, minVariance); float d = mean - moments.x; shadow = variance / (variance + (d * d)); return shadow; } } vec4 shadowCoord = shadowMatrix * vec4(viewSpacePosition, 1.0f); vec4 moments = texture(ShadowMap, shadowCoord.xy).xyzw; vec2 posMoments = vec2(moments.x, moments.z); vec2 negMoments = vec2(moments.y, moments.w); vec2 wDepth = warpDepth(shadowCoord.z); //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); shadow = min(posResult, negResult); 

Lamentablemente, no elimina el sangrado ligero. Hice algo mal ? ¿Tal vez debería calcular dos minVariance diferentes basados ​​en los exponentes positivos y negativos?

Edit1: Calculando minVariance de esta manera:

 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); 

da mejores resultados, pero la hemorragia leve todavía es bastante visible.

Edit2: sangrado ligero: EVSM con minVariance que se calcula como se indica arriba, proporciona un mejor resultado que VSM sin corrección estándar de sangrado ligero, pero para get el mejor resultado también uso el sangrado ligero estándar con EVSM. Se realiza una corrección de sangrado ligero en la function de Chebyshev, pero tal vez debería agregarlo después del siguiente cálculo: shadow = min (posResult, negResult)?

EVSM causa artefactos pequeños en el lado iluminado de los objects, así que agrego algunos glPolygonOffset al save la profundidad de EVSM.

El mapeo de sombras de varianza, en pocas palabras, simplemente sufre de estos problemas de sangrado ligero.

Personalmente prefiero implementar ESM (consulte la página 257 de ShaderX6) ya que la presión de memory es la mitad del map de VSM y los artefactos son mucho less abrasivos para mí: (El comienzo de la sombra es demasiado shiny).

Dicho esto, aquí hay un PDF (bastante antiguo) lleno de excelentes técnicas para hacerte pensar. (o simplemente para mostrarle el algorithm si no tiene ShaderX6) http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf

En mi motor actual, tengo un híbrido que es básicamente ESM, pero utiliza el map de sombras de 2 minutos (o superior) para calcular la varianza y networkingucir los artefactos de ESM en los lugares donde el oclusor está demasiado cerca del receptor.