3

我正在为延迟的 OpenGL 4.3 渲染器中的聚光灯做阴影映射。

我一直在尝试遵循有关该主题的一些教程,并在其后通过片段着色器进行建模,但我不明白的是计算阴影因子的最终比较。我从深度图(“”)中采样的值unifShadowTexture在 [0, 1] 的范围内,因为它直接来自深度缓冲区,但如何projCoords.z钳制到 [0, 1]?.w是否通过将其钳位到 [0,1] 来进行除法?我面临的问题是场景的主要部分是阴影,即使它不应该是,例如底层,在下图中(忽略光伪影,由于缺乏偏差 - 重点是模型亮了,但一楼没有):

在此处输入图像描述

const std::string gDirLightFragmentShader =
"#version 430                                                                                                                   \n \
                                                                                                                                \n \
layout(std140) uniform;                                                                                                         \n \
                                                                                                                                \n \
uniform UnifDirLight                                                                                                            \n \
{                                                                                                                               \n \
    mat4 mWVPMatrix;                                                                                                            \n \
    mat4 mVPMatrix;   // light view-projection matrix, pre-multiplied by the bias-matrix                                                                                                          \n \
    vec4 mLightColor;                                                                                                           \n \
    vec4 mLightDir;                                                                                                             \n \
    vec4 mGamma;                                                                                                                \n \
    vec2 mScreenSize;                                                                                                           \n \
} UnifDirLightPass;                                                                                                             \n \
                                                                                                                                \n \
layout (binding = 2) uniform sampler2D unifPositionTexture;                                                                     \n \
layout (binding = 3) uniform sampler2D unifNormalTexture;                                                                       \n \
layout (binding = 4) uniform sampler2D unifDiffuseTexture;                                                                      \n \
layout (binding = 5) uniform sampler2D unifShadowTexture;                                                                       \n \
                                                                                                                                \n \
out vec4 fragColor;                                                                                                             \n \
                                                                                                                                \n \
void main()                                                                                                                     \n \
{                                                                                                                               \n \
    vec2 texcoord = gl_FragCoord.xy / UnifDirLightPass.mScreenSize;                                                             \n \
                                                                                                                                \n \
    vec3 worldPos = texture(unifPositionTexture, texcoord).xyz;                                                                 \n \
    vec3 normal   = normalize(texture(unifNormalTexture, texcoord).xyz);                                                        \n \
    vec3 diffuse  = texture(unifDiffuseTexture, texcoord).xyz;                                                                  \n \
                                                                                                                                \n \
    vec4 lightClipPos = UnifDirLightPass.mVPMatrix * vec4(worldPos, 1.0);                                                      \n \
    vec3 projCoords   = lightClipPos.xyz / lightClipPos.w;                                                                   \n \
                                                                                                                                \n \
    float depthValue = texture(unifShadowTexture, projCoords.xy).x;                                                           \n \
    float visibilty  = 1.0;                                                                                                   \n \
    if (depthValue < (projCoords.z))                                                                                  \n \
         visibilty = 0.0;                                                                                                    \n \
                                                                                                                                \n \
    float angleNormal = clamp(dot(normal, UnifDirLightPass.mLightDir.xyz), 0, 1);                                               \n \
                                                                                                                                \n \
    fragColor = vec4(diffuse, 1.0) * visibilty * angleNormal * UnifDirLightPass.mLightColor;                                 \n \
}                                                                                                                               \n";
4

1 回答 1

2

除法w本身不会将其钳制为 [0,1]。从技术上讲,您拥有的是剪辑空间坐标,然后除以w将它们转换为 NDC 空间。对几何图形执行此操作时,任何 < -w 或 > w 的点 x、y 或 z 都会被剪裁。但是,当您在纹理坐标上执行此操作时,您仍然需要提供适当的纹理环绕模式(通常GL_CLAMP_TO_EDGE),因为坐标不会自动固定。

请注意,所有投影到阴影贴图远平面之外的点都将表现出相同的行为,因为坐标已被固定。通常这表现为超出一定距离的一切都完全处于阴影中。这就是为什么您希望阴影贴图的平截头体与衰减光量更紧密地匹配的原因。


此外,在这种情况下,asampler2DShadow很有意义......

这整件事:

float depthValue = texture(unifShadowTexture, projCoords.xy).x;
float visibilty  = 1.0;

if (depthValue < (projCoords.z))
  visibilty = 0.0;            

可以简化为:

float visibility = texture (unifShadowTexture, projCoords);

只要你做两件事:

  1. 声明unifShadowTexturesampler2DShadow
  2. 设置GL_TEXTURE_COMPARE_MODEGL_COMPARE_R_TO_TEXTURE您的深度纹理

这是有效的,因为对于sampler2DShadow,它需要 3D 纹理坐标。s并且t照常工作,并且r是它用于比较的值。默认比较函数是GL_LESS,因此您不必更改代码中的任何内容。给定一个GL_NEAREST纹理函数,它的返回将是1.00.0。它将产生与您上面的代码片段完全相同,但使用硬件功能进行实际深度测试,并且如果您启用GL_LINEAR.

但是,我建议您向纹理坐标的 Z 分量添加偏差。像 (0.001) 之类的东西,或者你会得到很多“阴影粉刺”,偏差太高,你会得到“彼得平移”(阴影似乎稍微悬停在它们所附着的任何东西上方)。

于 2014-01-19T20:32:15.733 回答