【发布时间】: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 得到什么,但它肯定是完全不同的。
【问题讨论】: