Monday, May 2, 2016

OpenGL exponential shadow mapping artifact

Leave a Comment

I'm trying to implement exponential shadow mapping (ESM) into my rendering engine but I'm facing some problems: I can get to see some shadows only if the exponential multiplier is less than 0, and the image becomes very dark.

I was already using Variance Shadow Maps, so I adapted my code to use ESM.

I've changed the fragment shader used to compute the shadow map like this:

#version 150 core  uniform float Exponential;    // Exponential multiplier term of the ESM equation  out float FragColor;  float map_01(float x, float v0, float v1) {     return (x - v0) / (v1 - v0); }  void main() {     float depthDivisor = (1.0 / gl_FragCoord.z);     float mappedDivisor = map_01(depthDivisor, 0.1f, 20.0f);    // Since my light is a directional light I force the near and far planes to 0.1 and 20.0     FragColor = exp(Exponential * mappedDivisor);      // VSM  float depth = gl_FragCoord.z;     // VSM  float dx = dFdx(depth);     // VSM  float dy = dFdy(depth);     // VSM  float moment2 = depth * depth + 0.25 * (dx * dx + dy * dy);     // VSM  FragColor = vec4(depth, moment2, 0.0, 1.0); } 

I've kept the same vertex shader for the shadow map:

in vec3 _position;  uniform mat4 ProjectionViewMatrix;   // Projection-View matrix of the light  layout(std140) uniform MOD {     mat4 AModelMatrix[20]; };  void main() {     gl_Position = ProjectionViewMatrix * AModelMatrix[gl_InstanceID] * vec4(_position, 1.0); } 

And I've changed the my directional light fragment shader to become like this:

uniform mat4 InverseProjectionViewMatrix; // Inverse of the camera projection-view matrix uniform float Exponential;                // Exponential multiplier term of the ESM equation (same as shadow map fragment shader) uniform mat4 ProjectionViewMatrix;        // Light projection view matrix  void main() {      vec3 genPos    = vec3((gl_FragCoord.x * InverseScreenSize.x), (gl_FragCoord.y * InverseScreenSize.y), 0.0f);      genPos.z       = texture(PrepassBuffer_DepthMap, genPos.xy).r;       vec4 clip          = InverseProjectionViewMatrix * vec4(genPos * 2.0f - 1.0f, 1.0f);      vec3 pos           = clip.xyz / clip.w;       vec4 shadowCoord   = ProjectionViewMatrix * vec4(pos, 1.0f);      shadowCoord        /= shadowCoord.w;      shadowCoord.xyz    = shadowCoord.xyz * vec3(0.5f, 0.5f, 0.5f) + vec3(0.5f, 0.5f, 0.5f);       float occluder = texture(DILShadowMap, shadowCoord.xy).r;      float reciever = map_01(shadowCoord.z, 0.1f, 20.0f);      float shadowAmount = saturate(occluder * exp(-Exponential * reciever));      ... } 

A couple of images to show the problem.

This is the result I get with Exponential set to 1.0 (no shadows at all):

This is the result I get with Exponential set to -30.0 (starting to see some shadows):

This is the result I get with the exact same coputations of the position (same vertex shaders basically) but with the variance shadow maps equation:

The only things I've changed from the algorithm I've found are these two lines in the shadow map fragment shader and in the directional light fragment shader:

// Shadow map fragment shader float depthDivisor = (1.0 / gl_FragCoord.z); // <- changed gl_FragCoord.z (originally was gl_FragCoord.w)  // Directional light fragment shader float reciever = map_01(shadowCoord.z, 0.1f, 20.0f); // <- changed shadowCoord.z (originally was shadowCoord.w) 

I've made these two changes because the W component was always 1.0, and it didn't seem correct to me to use W when the depth is stored into the Z component.

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment