使用OpenGL进行阴影贴图的硬件PCF

时间:2016-07-28 06:04:53

标签: opengl shadow-mapping

我在GeForce GTX 750下使用OpenGL 4.3来创建阴影贴图。现在,基本效果,如下所示,似乎是正确的: enter image description here 为了消除块效应,我试图在着色器中手动执行2x2 PCF。它导致以下结果,这似乎也是正确的: enter image description here 为了加速,我想使用图形卡提供的好处,它给出了比较结果的线性过滤器和一次获取。但效果与上述不同。 更像是OpenGL过滤阴影线性渲染,而不是阴影贴图上的滤镜enter image description here 下面是我如何做硬件PCF: 我注意到为了使用硬件PCF必须完成的基本两件事:

  1. 使用shadow类型的采样器,在我的情况下,samplerCubeShadow(我使用立方体贴图类型,因为我试图创建一个点光源场景)。
  2. 设置比较模式和过滤类型,在我的例子中,由以下代码完成:

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    
  3. 之后,我在着色器中使用texture这样的功能(我使用texture而不是textureProj的原因是因为后者似乎不支持立方体贴图阴影纹理,因为它需要vec5类型,显然还不支持):

    vec4 posInLight4D = positionsInLight / positionsInLight.w;    // divided by the 4-th component)
    vec3 texCoord = GetCubeMapTexCoord(posInLight4D.xy);    // get the texture coordinate in cube map texture. This can be assumed correct
    float lightness = texture(shadowMapHardware, vec4(texCoord, posInLight4D.z));
    

    但不幸的是,这给出了第三张图片中显示的结果。

    据我所知,通过设置比较模式线性过滤器,显卡将进行比较附近的2x2区域和线性插值结果并通过texture函数返回。我想我已经完成了所有必要的部分,但我仍然无法得到第二张图片中显示的确切结果。

    任何人都可以给我任何关于我可能出错的地方的建议吗?非常感谢。

    ps:有趣的是:我尝试了textureGather函数,它只返回比较结果,但没有进行过滤,它给出了精确结果,如第二张图所示。但这缺乏自动过滤程序,显然它不是硬件PCF的完整版本。

2 个答案:

答案 0 :(得分:2)

  

为了消除块状效果,我试图在着色器中手动执行2x2 PCF。它导致以下结果,这似乎也是正确的:

OpenGL规范没有规定线性插值深度比较时要使用的特定算法。但是,它通常将其描述为:

  

这个细节依赖于实现,但r应该   是[0,1]范围内的值,与比较次数成比例   传球或失败。

这不是很严格,它肯定不需要你认为“正确”的输出。

事实上,actual PCF与你想要的东西有很大的不同。你似乎想要的仍然是非常块状的;它只是不是二进制块。您的算法没有在比较结果之间进行线性插值;你刚刚进行了4次最近的比较并将它们平均化了。

NVIDIA给你的是PCD实际上假设的样子:比较结果之间的线性插值,基于你的采样点。

所以你的期望是错误的,而不是NVIDIA。

答案 1 :(得分:0)

在@Nicol的回答中,我想我误解了插值的含义。以下是我实现的着色器级插值,它看起来与问题中的第二张图片完全相同: enter image description here