2
\$\begingroup\$

I'm playing around in my little toy project to see if I can understand how exponential shadow mapping works. To begin, I have the following two fragment shaders:

Light depth texture shader

layout(location = 0) out float fragmentdepth;

void main(){
  fragmentdepth = gl_FragCoord.z;
}

Main shader

...
vec3 shadowDiv = shadowCoords.xyz / shadowCoords.w;
float lightDepth = texture(depthMap, shadowDiv.xy);
float visibility = clamp(exp(-70 * shadowDiv.z) * exp(70 * lightDepth), 0, 1);
...

This works fine - I have shadows where I expect them, and I'm using the approximation to the boolean function by taking the product of exponentials, as shown in the ESM paper.

However, my understanding is that the whole point of this, is that I can move exp(70 * lightDepth) out of this shader, and into the shader when I generate the depth texture at the light. That is:

New light depth texture shader

layout(location = 0) out float fragmentdepth;

void main(){
  fragmentdepth = exp(70 * gl_FragCoord.z);
}

Main shader

...
vec3 shadowDiv = shadowCoords.xyz / shadowCoords.w;
float lightDepth = texture(depthMap, shadowDiv.xy);
float visibility = clamp(exp(-70 * shadowDiv.z) * lightDepth, 0, 1);
...

When I make this change, the entire scene becomes shadowed. I'm sure I'm misunderstanding something somewhere, but I'm not sure where. I have tried varying the constant term (70) between 1 and 70, though this doesn't appear to make a difference. I have no errors reported by KHR_debug

I am creating my light depth texture as:

genLightDepthMap :: IO GLTextureObject
genLightDepthMap =
  do lightDepthMap <- overPtr (glGenTextures 1)
     glBindTexture GL_TEXTURE_2D lightDepthMap
     glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR
     glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR
     glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_CLAMP_TO_EDGE
     glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_CLAMP_TO_EDGE
     glTexImage2D GL_TEXTURE_2D
                  0
                  GL_DEPTH_COMPONENT24
                  shadowMapResolution
                  shadowMapResolution
                  0
                  GL_DEPTH_COMPONENT
                  GL_FLOAT
                  nullPtr
\$\endgroup\$
1
\$\begingroup\$

You are using GL_DEPTH_COMPONENT24 which is a fixed-point format clamped to the range [0, 1] inclusively.

The floating point formats are GL_DEPTH_COMPONENT32F and DEPTH32F_STENCIL8.

 glTexImage2D GL_TEXTURE_2D
              0
              GL_DEPTH_COMPONENT32F
              shadowMapResolution
              shadowMapResolution
              0
              GL_DEPTH_COMPONENT
              GL_FLOAT
              nullPtr

You also need to call glDepthRange(-1, 1); to disable scaling & offsetting of the depth values.

It is unclear if you can call glClearDepth(INFINITY) or need to clear the depth using a full-screen quad as the ARB_depth_buffer_float extension says "ClearDepth takes a floating-point value that is clamped to the range[0, 1]."

I don't know how supported it would be to clear the depth with a quad at depth near-infinity regarding clipping against the far plane: The clipping calculation might go nuts with rounding errors.

Your best bet is to draw a fullscreen quad at a reasonable depth (1.0) with depth-test disabled and FORCE the depth at INFINITY (or a very large non-infinity value) in the pixel shader so this will happen after primitive clipping.

Cheers,

\$\endgroup\$
  • \$\begingroup\$ Thanks, I'll be sure to look into this! I literally just found another solution, which is to render into a GL_R32F texture, as a color texture rather than depth. I'm curious if that has drawbacks against using GL_DEPTH_COMPONENT \$\endgroup\$ – ocharles Dec 10 '14 at 22:35
  • 1
    \$\begingroup\$ Its essentially the same thing, except that you ALSO need a depth buffer to do depth test. So on one hand you're doubling the memory requirement, on the other hand you're not modifying the fragment depth value anymore which is good as changing the fragment depth value can incur a huge performance cost as depth-test cannot happen before the fragment shader has run disabling early-Z test and hi-Z test. \$\endgroup\$ – Stephane Hockenhull Dec 10 '14 at 22:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.