Issue using 2D depth texture array and regular depth texture in same shader

Started by
11 comments, last by Silverlan 9 years, 2 months ago

I'm using a texture array for cascaded shadow maps, and regular depth textures for spot-lights. They work fine, as long as I don't have them active at the same time in my shader.

In fact, after some testing, I found out that as soon as I bind ANY other depth texture to the shader, the shadows from the texture array are rendered incorrectly.

Here are the relevant snippets from the shaders / code:

Generating the shadow texture array:


unsigned int frameBuffer;
glGenFramebuffers(1,&frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER,frameBuffer);
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D_ARRAY,texture);
 
glTexImage3D(
    GL_TEXTURE_2D_ARRAY,0,GL_DEPTH_COMPONENT24,
    size,size,GetSplitCount(),1,GL_DEPTH_COMPONENT,GL_FLOAT,NULL
);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE);
 
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER);
glFramebufferTextureLayer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,texture,0,0);

The fragment shader function for the texture lookup:


float CalculateShadowTerm(sampler2DArrayShadow shadowMap,vec4 worldCoord,float bias)
{
    int index = numCascades -1;
    mat4 vp;
    for(int i=0;i<numCascades;i++)
    {
        if(gl_FragCoord.z < csmFard[i])
        {
            vp = csmVP[i];
            index = i;
            break;
        }
    }
    vec4 shadowCoord = vp *worldCoord;
    shadowCoord.w = shadowCoord.z *0.5f +0.5f -bias;
    shadowCoord.z = float(index);
    shadowCoord.x = shadowCoord.x *0.5f +0.5f;
    shadowCoord.y = shadowCoord.y *0.5f +0.5f;
 
    return shadow2DArray(shadowMap,shadowCoord +vec4(
        offset.x *shadowRatioX *shadowCoord.w,
        offset.y *shadowRatioY *shadowCoord.w,
        0.0,
        0.0
    )).x;
}

The result is essentially just multiplied with the output color.

This is working as it should (At the top in the image are the contents of the 4 cascades):

http://puu.sh/f1p23/d9f5549847.jpg

However, as soon as I add any texture look-up to a different depth texture anywhere in the fragment shader, it suddenly gets rendered incorrectly.

Here's the second depth texture for testing purposes:


unsigned int frameBuffer;
glGenFramebuffers(1,&frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER,frameBuffer);
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D,texture);
glTexImage2D(
    GL_TEXTURE_2D,0,
    GL_DEPTH_COMPONENT16,
    128,128,0,
    GL_DEPTH_COMPONENT,GL_FLOAT,(void*)0
);
 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,0);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,texture,0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
Fragment Shader:

uniform sampler2D testShadowMap;
void main()
{
    texture(testShadowMap,vec2(0,0));
    [...]
}

This shouldn't do anything whatsoever, and they're bound to different texture units, however suddenly the result is this:

http://puu.sh/f1p9R/92e86e22b7.jpg

Each cascade is now rendered with different intensity, even though the actual contents in the depth textures is the same as before.

It looks like 'shadow2DArray' suddenly doesn't seem to do the actual depth comparison anymore and just returns the actual depth value (Value between 0 and 1).

If I bind any non-depth texture instead of the test-texture, or if I just comment out the texture lookup ('testShadowMap'), it works again.

What's going on here?

Advertisement

For me it seems that something with the sampler bindings is not how you think it is. When you get changes by commenting out something arbitrary and it works, most likely you do a binding with this call, that does affect the gl state where you don't expect it. Could you make sure that your two textures are bound to different texture units? Or could you post your code where you actually do the binding? Do you bind samplers as well? Because I can't find any "glActiveTexture" statements in your code.

For me it seems that something with the sampler bindings is not how you think it is. When you get changes by commenting out something arbitrary and it works, most likely you do a binding with this call, that does affect the gl state where you don't expect it. Could you make sure that your two textures are bound to different texture units? Or could you post your code where you actually do the binding? Do you bind samplers as well? Because I can't find any "glActiveTexture" statements in your code.

Thanks for the response.

As I've said, they're bound to different texture units:

Spotlight:


glActiveTexture(GL_TEXTURE0 +SHADER_SHADOW_MAP_TEXTURE_START +idxSpot);
glBindTexture(GL_TEXTURE_2D,shadow->GetDepthTexture());
glActiveTexture(GL_TEXTURE0);
idxSpot++;

Directional light:


glActiveTexture(GL_TEXTURE0 +SHADER_SHADOW_MAP_TEXTURE_START +idxDirectional +CGame::MAX_ACTIVE_LIGHTS_PER_ENTITY *2);
glBindTexture(GL_TEXTURE_2D_ARRAY,shadow->GetDepthTexture());
glActiveTexture(GL_TEXTURE0);
idxDirectional++;

'SHADER_SHADOW_MAP_TEXTURE_START' is a constant set to 20. Since there's only one spotlight and one directional light in the example scene, 'idxSpot' and 'idxDirectional' are both 0. 'MAX_ACTIVE_LIGHTS_PER_ENTITY' is a constant set to 8.

So, in essence, the texture unit for the spotlight shadow is (GL_TEXTURE0 +20) and for the directional shadow it's (GL_TEXTURE0 +28).

I'm not using any samplers either.

Ok, seems to be okay, I just wanted to be sure.

And you evaluate all lights in a single draw call (forward rendering), so you use your texture array and the single depth texture in the same fragment shader? What exactly are you doing with the sample from the single depth texture? Because in your code snippet, you don't use the sample, so the compiler will most likely throw this statement away. If possible, just post the complete fragment shader code - maybe then, things will clear up - or else I'm afraid I cant find your mistake either :)

And you evaluate all lights in a single draw call (forward rendering), so you use your texture array and the single depth texture in the same fragment shader? What exactly are you doing with the sample from the single depth texture? Because in your code snippet, you don't use the sample, so the compiler will most likely throw this statement away. If possible, just post the complete fragment shader code - maybe then, things will clear up - or else I'm afraid I cant find your mistake either smile.png

I trimmed the fragment shader down to the essential parts (Which still cause the issue):

http://pastebin.com/QcQnBtpa

This is the result if 'SPOTLIGHT_TEST' is set to '0' (Spotlight deactivated):

http://puu.sh/fpqij/7eeeff5906.jpg

This is the result if 'SPOTLIGHT_TEST' is set to '1' (Spotlight activated):

http://puu.sh/fpqgP/8bf754dce2.jpg

This is the result if 'SPOTLIGHT_TEST' is set to '2' (Spotlight activated, but the result of the shadow lookup is ignored):

http://puu.sh/fpqtd/d7ea652d78.jpg

Basically, as soon as there's any lookup for the shadow map of the spotlight, the issue occurs, even if the result is not used at all.

Puh, I tried to find any mistake for half an hour, but it should work as it is... so I have to continue with stupid questions:

Can you remove the spot light shadow map sample completely and replace it with a hardcoded 0.5 or something, so that we can be sure you don't have a sampling instruction in your compiled shader? When you have the spotlight activated (but now without shadows), does it work?

I hope at least this works - if not, could you try to rename one of your shadow-sample-methods, so that is doesn't use overloaded methods any more?

Sorry for my stupid assumptions, but in the past, I had so many unbelievable stupid compile- and runtime errors with opengl.

Can you remove the spot light shadow map sample completely and replace it with a hardcoded 0.5 or something, so that we can be sure you don't have a sampling instruction in your compiled shader? When you have the spotlight activated (but now without shadows), does it work?

All I have to do to make it work is remove the lookup into the shadow map ('shadow2DProj').

As soon as there's ANY lookup into the shadow map, the problem occurs. I've tried other lookup-functions instead of 'shadow2DProj' (e.g. 'texture2D'), however that didn't help either.

The shadow map itself is not at fault either, it's the same if I use any other depth texture. If I use an additional RGB texture instead, the problem doesn't occur.

I hope at least this works - if not, could you try to rename one of your shadow-sample-methods, so that is doesn't use overloaded methods any more?

I tried renaming one of the functions, but the result is still the same.

err... update drivers?

o3o

err... update drivers?

My drivers are up to date and my graphics card isn't that old either (AMD Radeon HD 7870).

I did make some progress however.

I basically ended up binding the shadow map of my spotlight to ALL samplers in the shadow map array ('shadowMaps'), and now it works as it should:

http://puu.sh/ft0N9/8cab0af7a7.jpg

If just one texture in the array (Regardless of whether the texture is actually being used) is bound to an invalid texture (e.g. '0'), the problem occurs.

So the problem seems to be fixed now, but I don't really understand what's going on here. Is this a hardware-dependent thing, or part of the OpenGL specification?

Sorry I'm afraid I'm not able to follow you. What do you mean by "binding the shadow map of my spotlight to ALL samplers in the shadow map array" ? I thought you didn't use texture arrays for your spotlight depth maps? You have to bind your array texture from your cascaded shadow map for your directional light and then, you bind some regular textures to some other units, you got that, or did I miss the point?

This topic is closed to new replies.

Advertisement