Can you use sampler2D and sampler2DShadow on the same texture?

I want to implement percentage closer soft shadows (PCSS). The blocker search looks for depth values so I must use sampler2D, which requires a GLSL texture() function that returns a depth value. However, when rendering the final shadow, I would like to take advantage of hardware PCF by using sampler2DShadow which requires a texture() function that does the depth compare for you and does not return a depth value.

The simplest solution I could think of is to use both samplers on the same texture. However, it appears that sampler2DShadow requires you to set GL_TEXTURE_COMPARE_MODE to GL_COMPARE_R_TO_TEXTURE for the texture, and sampler2D requires to you not set GL_TEXTURE_COMPARE_MODE. And then the samplers don’t appear to both work on the same texture.

Is there any trick to use both samplers on the same texture, or do I need to do something heavy-handed like use two textures?

There is a trick: use two separate sampler objects. Sampler Objects store the sampling state for a texture access. This includes things like depth comparison.

Now, this means that your two sampler variables in GLSL must use different texture units, and therefore you must bind the same texture twice:


glBindSampler(0, nearestFiltering);
glBindTextureUnit(0, theTexture);
glBindSampler(1, depthComparison);
glBindTextureUnit(1, theTexture);

//In GLSL

layout(binding = 0) sampler2D unfiltered;
layout(binding = 1) sampler2DShadow pcfTexture;

Ah, thank you. I’ve never even heard of the layout qualifier before. While I was sitting here hoping for a reply I figured out another trick for doing this (which seems easier for me because there are a couple layers of high-level rendering libraries between my application code and the OpenGL):

I can set up a sampler2D and a sampler2DShadow and set GL_TEXTURE_COMPARE_MODE to GL_COMPARE_R_TO_TEXTURE. Reading from sampler2D would fail, but it works if I use texelFetch() instead instead of texture().

sampler2D shadowMap;
sampler2DShadow shadowMapHardwarePCF;

// in the blocker search:
float depth = texelFetch(shadowMap, ivec2(uv.xy * textureSize + 0.5), 0).x;
// In the shadow rendering
shadow += texture(shadowMapHardwarePCF, uv.xyz);

Unfortunately, I have no idea if this is a legitimate way to solve this problem or if I’m just getting lucky because I have a permissive OpenGL driver :slight_smile: