PDA

View Full Version : try to emulate hardware shadow mapping



shapeare
12-01-2011, 03:53 AM
It is well-known that if the function textureProj takes in a sampler2DShadow type argument, it will performs a 4-sample PCF when the linear filtering is turned on. Now, I want to perform PCF by myself rather than rely on hardware, but I failed.

I will state how I implemented the regular shadow mapping (section 1), and how I tried to emulate PCF (section 2 & 3).

1. the regular shadow mapping
I created the depth texture object using the following code:
<code>
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &amp;depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);

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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 512, 512, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
</code>
Nothing special here.

In the fragment shader, the texture uniform is defined as
<code>
uniform sampler2DShadow depthTex;
</code>
then use the following function to directly return a value that represents how much the current fragment is in shadow:
<code>
float shadeFactor = textureProj(depthTex, texPos);
</code>
Refer to Figure 1 for the result.
http://graphicsprojects.files.wordpress.com/2011/12/directshadow_textureproj.png

2. 16-sample PCF
I use the technique described in GPU Gems - Chapter 11. Shadow Map Antialiasing (http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html) to improve the shadow.

The change from last program only lies in the fragment shader. The following function can be used to do a projected texture map read with an offset given in texel units. The variable texmapscale is a vec2 containing 1/width and 1/height of the shadow map.
<code>
float offset_lookup(sampler2DShadow map, vec4 loc, vec2 offset)
{
vec2 texmapscale = vec2(1/512.0, 1/512.0);
return textureProj(map, vec4(loc.xy + offset * texmapscale * loc.w, loc.z, loc.w));
}
</code>
The implement of 16-sample version in a fragment program is as follows:
<code>
float sum = 0;
float x, y;

for (y = -1.5; y <= 1.5; y += 1.0)
for (x = -1.5; x <= 1.5; x += 1.0)
sum += offset_lookup(depthTex, texPos, vec2(x, y));

float shadeFactor = sum / 16.0;
</code>
The result is shown here.
http://graphicsprojects.files.wordpress.com/2011/12/post3.png

3. My attempt to emulate the hardware PCF effect

What I have done here is to turn off the GL_TEXTURE_COMPARE_MODE by setting it to GL_NONE, so the textureProj function will not do a comparison, and the expected return value from textureProj should be the depth value in the sampled texture. In addition, I manually did a comparison between the current depth value and the depth value in the texture as follows:
<code>
if(texCoord.z < depth)
return 1.0;
else
return 0;
</code>
But this time, the result was not as expected. The area within the view of the light was all black, as if all the comparisons returned 0 (Figure 3).
http://graphicsprojects.files.wordpress.com/2011/12/post4.png

Therefore I tried another way. Changed the definition of the texture uniform to
<code>
uniform sampler2D depthTex;
</code>
therefore the function textureProj no longer takes in a sampler2DShadow, so it and returns a vec4, which should be the depth value in the texture. I took the value from the R channel and compared with the depth of the fragment, but the result was also out of expected (Figure 4).
http://graphicsprojects.files.wordpress.com/2011/12/post5.png

The problem is why the result in my last step is different from the beginning one? How can I emulate the hardware PCF.


Thanks in advance.

_arts_
12-01-2011, 09:13 AM
It is well-known that if the function textureProj takes in a sampler2DShadow type argument, it will performs a 4-sample PCF when the linear filtering is turned on.

As far as I know it depends on the hardware/driver.



if(texCoord.z < depth)
return 1.0;
else
return 0;

I am not sure what you do here. You should compare the value in the texture with the z texture coordinate.

Here is a tutorial about PCF, might be useful: http://fabiensanglard.net/shadowmappingPCF/index.php

See this one for texture comparison without using Sampler2DShadow: http://fabiensanglard.net/shadowmapping/index.php

shapeare
12-01-2011, 05:42 PM
Thank you for your reply. I read the article you mentioned above, but what I want is to do a depth comparison by myself when the GL_TEXTURE_COMPARE_MODE is set to GL_NONE.

Instead of rely on the sampling function to return a comparison result, I would like to fetch the depth value from the texture and compare that with the depth of the fragment. It is what I have done in my code, but it generates the false result.

shapeare
12-03-2011, 03:57 AM
I must admit that my first post is too long. Now I am going to put my questiones one by one:

Here comes my first problem:

if the parameters of the depth texture object is like this:


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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);

(notice: the value for GL_TEXTURE_COMPARE_MODE is GL_NONE.)
and in the fragment shader, the declaration of the texture is like:


uniform sampler2DShadow depthTex;

what can I get from:


float depth = textureProj(depthTex, texPos);

(notice: texPos is a vec4 variable used to sample the texture.)

Suppose this function returns the depth value from the texture, then I manually compare that with texPos.z/texPos.w, like:


if(texPos.z/texPos.w < depth)
oColor = lightColor ;
else
oColor = vec4(0, 0, 0, 1.0);

but the result is out of expected.

Alfonse Reinheart
12-03-2011, 11:31 AM
what can I get from:

Nothing. If you use a Shadow sampler type (http://www.opengl.org/wiki/GLSL_Sampler#Shadow_samplers) in GLSL, the texture must have a COMPARE_MODE that is not NONE. Otherwise, you get either undefined behavior or a GL error. Probably the former.

thokra
12-03-2011, 12:27 PM
Just to add to Alfonse's remark: You can also do shadow mapping using REGULAR samplers with GL_COMPARE_MODE == GL_NONE and implement the whole procedure yourself.

This is actually the proposed approach for implementing percentage closer softshadows.

shapeare
12-04-2011, 02:00 AM
Cheers.

I finally found the problem. When trying to emulate the hardware PCF, not only need to set GL_COMPARE_MODE to GL_NONE, but also need to set GL_TEXTURE_MAG_FILTER to GL_NEAREST, then the interpolation in the shader will generate correct result.