阴影贴图和深度值混淆

凯撒·约翰(KaiserJohaan)

我在延迟的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";
安东·科尔曼(Andon M.Coleman)

The division by w by itself will not clamp it to [0,1]. Technically what you have are clip-space coordinates, and then division by w transforms them into NDC space. Any point x, y, or z that is < -w or > w is clipped when this operation is performed on geometry. However, when you do it on your texture coordinates you still need to provide an appropriate texture wrap mode (usually GL_CLAMP_TO_EDGE), because the coordinates are not clamped automatically.

Note that all points that project beyond your shadow map's far plane will exhibit the same behavior since the coordinates are clamped. Usually this manifests itself as everything beyond a certain distance being fully in shadow. This is why you want to match your shadow map's frustum more closely with your attenuated light volume.


Also, in this situation a sampler2DShadow makes a lot of sense...

This whole thing:

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

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

Can be simplified to this:

float visibility = texture (unifShadowTexture, projCoords);

Provided you do two things:

  1. Declare unifShadowTexture as sampler2DShadow
  2. Set GL_TEXTURE_COMPARE_MODE to GL_COMPARE_R_TO_TEXTURE for your depth texture

This works because for sampler2DShadow, it requires 3D texture coordinates. s and t work as usual, and r is the value it uses for comparison. The default comparison function is GL_LESS, so you do not have to change anything in your code. Given a GL_NEAREST texture function, the return of this will be either 1.0 or 0.0. It will produce exactly the same as your code snippet above, but using a hardware feature for the actual depth test and will often improve performance and get you inexpensive PCF if you enable GL_LINEAR.

但是,我建议您向纹理坐标的Z分量添加一个偏差。像(0.001)之类的东西,或者您会得到很多“粉刺痤疮”,偏见太高,您会得到“ peting panning”(阴影似乎悬停在它们所附着的物体之上)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

阴影贴图和深度值混淆

来自分类Dev

阴影贴图:整个网格都在阴影中,根据深度贴图应该没有光线的地方

来自分类Dev

阴影贴图的位置和分辨率

来自分类Dev

SSAO 和阴影贴图 | 阴影不适用于 SSAO

来自分类Dev

如何正确制作用于阴影贴图的深度立方体贴图?

来自分类Dev

OpenGL FBO深度格式和类型混淆

来自分类Dev

阴影贴图工件

来自分类Dev

OpenGL中的阴影贴图

来自分类Dev

(阴影贴图)将深度缓冲区渲染为纹理并进行绘制以进行检查

来自分类Dev

GLSL 1.20阴影贴图,使阴影变形

来自分类Dev

OpenGL阴影贴图-阴影位置错误

来自分类Dev

向Android工具栏添加阴影和深度

来自分类Dev

将2D和3D阴影贴图发送到着色器

来自分类Dev

OpenGL阴影贴图几乎可以正常工作

来自分类Dev

OpenGL Variance阴影贴图倒置衰减

来自分类Dev

级联阴影贴图不太正确

来自分类Dev

具有延迟渲染的阴影贴图

来自分类Dev

巴比伦JS中的阴影贴图

来自分类Dev

级联阴影贴图无法正常工作

来自分类Dev

如何使用phong阴影实现凹凸贴图

来自分类Dev

聚光灯阴影贴图的计算偏差

来自分类Dev

阴影贴图-将视图空间位置转换为阴影贴图空间

来自分类Dev

阴影贴图-将视图空间位置转换为阴影贴图空间

来自分类Dev

应用位移贴图和镜面贴图

来自分类Dev

如何在Qt / QML中实现3D深度和阴影?

来自分类Dev

360 FOV深度缓冲区(按拓扑和2D阴影)

来自分类Dev

OpenGL阴影贴图移动版不起作用

来自分类Dev

Javascript Three.JS阴影贴图不起作用

来自分类Dev

OpenGL阴影贴图在所有对象上均相同