View Full Version : Can you use sampler2D and sampler2DShadow on the same texture?

10-06-2017, 12:31 PM
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?

Alfonse Reinheart
10-06-2017, 01:12 PM
There is a trick: use two separate sampler objects. Sampler Objects (https://www.khronos.org/opengl/wiki/Sampler_Object) store the sampling state for a texture access. This includes things like depth comparison (https://www.khronos.org/opengl/wiki/Sampler_Object#Comparison_mode).

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


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

10-06-2017, 03:55 PM
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 :)