【问题标题】:GLSL shadow mapping: shadow2DProj causes rendering artifactsGLSL 阴影映射:shadow2DProj 导致渲染伪影
【发布时间】:2019-11-13 20:54:02
【问题描述】:

设法让阴影映射在我的 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);
} 

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

看了关于阴影粉刺的描述,这似乎是同样的现象(来源: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 得到什么,但它肯定是完全不同的。

【问题讨论】:

    标签: opengl glsl


    【解决方案1】:

    这个问题对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;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-02-04
      • 1970-01-01
      • 2014-01-16
      • 2014-05-17
      • 2015-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      相关资源
      最近更新 更多