OpenGL中级联阴影贴图纹理访问漏洞

4

我正在尝试实现级联阴影贴图,但当我想要访问每个视锥体分区对应的深度纹理时,出现了一个错误。

更具体地说,我的问题出在当我想要选择正确的阴影纹理时,如果我尝试使用下面的代码,我会得到像这张图片中一样的伪影效果。您正在看一个立方体的阴影,伪影是被切割视锥体限制(红色表示近端剪裁面,绿色表示远端剪裁面)之间的小点/正方形。

uniform sampler2D   shadowMaps[10];         //GL_TEXTURE5

uniform float       cameraFrustumZPartitionning[10];
uniform int         cameraFrustumSize;

int getCSMlevel(float Z){
    for(int iZ = 0 ; iZ < cameraFrustumSize; ++iZ)
        if(Z < cameraFrustumZPartitionning[iZ])
            return iZ;
    return -1;
}


float ShadowCalculation(vec4 fragPosLightSpace[3], int shadowMapId, float NdotD) //WIP
{
    int csmLevel = getCSMlevel(ClipSpacePosZ);

    vec4 fragPosLS = fragPosLightSpace[csmLevel];
    vec3 projCoords = fragPosLS.xyz / fragPosLS.w;

    // Transform to [0,1] range
    projCoords = projCoords * 0.5 + 0.5;

    float closestDepth = 0.0;


    if(csmLevel == -1)
        return 0.0;
    closestDepth = texture(shadowMaps[csmLevel], projCoords.xy).r;

    return 1.0 - ((projCoords.z  > closestDepth)?1.0:0.0);
}

如果我尝试这个代码,一切都很好。

uniform sampler2D   shadowMaps[10];         //GL_TEXTURE5

uniform float       cameraFrustumZPartitionning[10];
uniform int         cameraFrustumSize;

int getCSMlevel(float Z){
    for(int iZ = 0 ; iZ < cameraFrustumSize; ++iZ)
        if(Z < cameraFrustumZPartitionning[iZ])
            return iZ;
    return -1;
}


float ShadowCalculation(vec4 fragPosLightSpace[3], int shadowMapId, float NdotD) //WIP
{
    int csmLevel = getCSMlevel(ClipSpacePosZ);

    vec4 fragPosLS = fragPosLightSpace[csmLevel];
    vec3 projCoords = fragPosLS.xyz / fragPosLS.w;

    // Transform to [0,1] range
    projCoords = projCoords * 0.5 + 0.5;

    float closestDepth = 0.0;



    if(csmLevel == 0)
        closestDepth = texture(shadowMaps[0], projCoords.xy).r;
    else if(csmLevel == 1)
        closestDepth = texture(shadowMaps[1], projCoords.xy).r;
    else if(csmLevel == 2)
        closestDepth = texture(shadowMaps[2], projCoords.xy).r;
    else
        return 0.0;

    return 1.0 - ((projCoords.z  > closestDepth)?1.0:0.0);
}

在GLSL中,我们可以制作sampler2D的数组,并通过使用变量访问该数组来获取正确的值,或者我在这里犯了一个巨大的错误?
1个回答

2

来自GLSL 4.50规范:

当采样器在着色器中被聚合成数组时,只能用动态统一整数表达式索引采样器,否则结果将是未定义的。

这意味着所有片段着色器调用都应该评估使用相同的索引。你的第一个代码明显不满足这一点。在第二个版本中,执行明显分歧,因此对于每个代码路径,索引都是动态统一的。

编辑:由于您的阴影贴图可能具有相同的大小,因此可以使用数组纹理。(数组纹理不是采样器数组。)


我以为这只是用于数组的声明,但在这个教程(http://ogldev.atspace.co.uk/www/tutorial49/tutorial49.html)中他们这样做了,我错过了什么或者我真的不理解动态均匀整数表达式的含义。 - guillaume voisin
很遗憾,它们的大小不一样。 - guillaume voisin
那个引用谈到了索引。另一方面,数组的大小必须是常量表达式,这比动态均匀表达式更强。此外,教程可能是错误的。 - Yakov Galka
我成功地让它工作了,多亏了你。我一直在循环一个均匀的整数,因此我的索引不是一个动态均匀的整数表达式。相反,在主函数中循环一个常量值,现在它正常工作了。非常感谢! - guillaume voisin
我看了教程,那里的所有阴影贴图都是相同大小的,所以纹理数组听起来对你来说是一个可行的解决方案。 - Yakov Galka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接