GLSL阴影映射:shadow2DProj导致呈现伪像

设法使Shadow Mapping在我的OpenGL渲染引擎中工作,但是它产生了一些我认为是“暗疮”的怪异伪像。但是,我正在使用shadow2DProj从阴影深度贴图获取阴影值,对我而言,这已被证明是使阴影完全显示的唯一方法。因此,在learnopengl的各种教程,opengl-tutorials和其他教程中浏览并没有产生任何帮助。想获得一些有关如何缓解此问题的建议。

这是我用来绘制阴影贴图的着色器:

#version 330 core

out vec4 FragColor; 

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    vec3 attenuation;
};

in vec3 FragPos;  
in vec3 Normal;  
in vec2 TexCoords;
in vec4 ShadowCoords;

uniform vec3 viewPos;
uniform sampler2D diffuseMap;
uniform sampler2D specularMap;
uniform sampler2DShadow shadowMap;
uniform Light lights[4];
uniform float shininess;

float calculateShadow(vec3 lightDir)
{
    float shadowValue = shadow2DProj(shadowMap,ShadowCoords).r;
    float shadow = shadowValue;
    return shadow;
}

vec3 calculateAmbience(Light light,vec3 textureMap)
{
    return light.ambient * textureMap;
}

void main()
{
    vec4 tex = texture(diffuseMap,TexCoords);

    if (tex.a < 0.5)
    {
        discard;
    }

    vec3 ambient = vec3(0.0);
    vec3 diffuse = vec3(0.0);
    vec3 specular = vec3(0.0);

    vec3 norm = normalize(Normal);
    vec3 viewDir = normalize(viewPos - FragPos);

    for (int i = 0; i < 4; i++)
    {
        ambient = ambient + lights[i].ambient * tex.rgb;

        vec3 lightDir = normalize(lights[i].position - FragPos);
        float diff = max(dot(norm,lightDir),0.0);
        diffuse = diffuse + (lights[i].diffuse * diff * tex.rgb);

        vec3 reflectDir = reflect(-lightDir,norm);
        float spec = pow(max(dot(viewDir,reflectDir),0.0),shininess);
        specular = specular + (lights[i].specular * spec * tex.rgb);

        float dist = length(lights[i].position - FragPos);
        float attenuation = lights[i].attenuation.x + (lights[i].attenuation.y * dist) + (lights[i].attenuation.z * (dist * dist));
        if (attenuation > 0.0)
        {
            ambient *= 1.0 / attenuation;
            diffuse *= 1.0 / attenuation;
            specular *= 1.0 / attenuation;
        }
    }

    float shadow = calculateShadow(normalize(lights[0].position - FragPos));
    vec3 result = (ambient + (shadow) * (diffuse + specular));
    FragColor = vec4(result,1.0);
} 

这是我得到的结果。注意立方体顶部的怪异条纹:

GLSL阴影映射:shadow2DProj导致呈现伪像

阅读有关暗疮的描述,这似乎是相同的现象(来源:https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping)。

根据那篇文章,我需要检查ShadowCoord深度值(减去偏置常数)是否低于从阴影贴图读取的阴影值。如果是这样,我们就有阴影。现在...问题来了。由于我使用shadow2DProj而不是texture()从阴影贴图中获取阴影值(毫无疑问,是通过一些复杂的魔术),因此我无法将该文章的代码“移植”到我的着色器中并使其正常工作。这是我尝试过的:

float calculateShadow(vec3 lightDir)
{
    float closestDepth = shadow2DProj(shadowMap,ShadowCoords).r;
    float bias = 0.005;
    float currentDepth = ShadowCoords.z;
    float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
    return shadow;
}

但是这根本不会产生阴影,因为“阴影”浮点数始终从深度和偏差检查中分配为1.0。我必须承认,与texture(...)。r相比,我不完全了解我使用shadow2DProj(...)。r会得到什么,但这肯定是完全不同的。

sunbowen1987 回答:GLSL阴影映射:shadow2DProj导致呈现伪像

这个问题对shadow2DProj的作用有误解。该函数不返回深度值,而是返回深度比较结果。因此,请在调用前应用偏见。

解决方案1 ​​

在运行比较之前应用偏差。 ShadowCoords.z 是您的currentDepth值。

float calculateShadow(vec3 lightDir)
{
  const float bias = 0.005;
  float shadow = shadow2DProj(shadowMap,vec3(ShadowCoords.uv,ShadowCoords.z - bias)).r;
  return shadow;
}

解决方案2

在执行光空间深度传递时施加偏压。

glPolygonOffset(float factor,float units)

此函数将Z轴值偏移factor * DZ + units,其中DZ是多边形的Z轴斜率。将此值设置为正值将使多边形更深地进入场景,就像我们的偏见一样。

初始化期间:

glEnable(GL_POLYGON_OFFSET_FILL);

光深传递期间:

// These parameters will need to be tweaked for your scene 
// to prevent acne and mitigate peter panning
glPolygonOffset(1.0,1.0); 

// draw potential shadow casters

// return to default settings (no offset)
glPolygonOffset(0,0); 

着色器代码:

// we don't even need the light direction for slope bias
float calculateShadow() 
{
  float shadow = shadow2DProj(shadowMap,ShadowCoords).r;
  return shadow;
}
本文链接:https://www.f2er.com/3106842.html

大家都在问