C++ 阴影贴图产生不正确的结果

C++ 阴影贴图产生不正确的结果,c++,opengl,glsl,shadow-mapping,C++,Opengl,Glsl,Shadow Mapping,我试图在延迟渲染管道中实现阴影映射,但实际上我遇到了一些问题,即生成阴影映射,然后对像素进行阴影处理——我认为应该进行阴影处理的像素根本不存在 我有一个单向光,它是我引擎中的“太阳”。我已经推迟了灯光的渲染设置,到目前为止效果良好。我使用以下代码生成视图矩阵,再次将场景渲染为阴影贴图的仅深度FBO: glm::vec3 position = r->getCamera()->getCameraPosition(); // position of level camera glm::ve

我试图在延迟渲染管道中实现阴影映射,但实际上我遇到了一些问题,即生成阴影映射,然后对像素进行阴影处理——我认为应该进行阴影处理的像素根本不存在

我有一个单向光,它是我引擎中的“太阳”。我已经推迟了灯光的渲染设置,到目前为止效果良好。我使用以下代码生成视图矩阵,再次将场景渲染为阴影贴图的仅深度FBO:

glm::vec3 position = r->getCamera()->getCameraPosition(); // position of level camera
glm::vec3 lightDir = this->sun->getDirection(); // sun direction vector
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,20); // ortho projection
glm::mat4 depthViewMatrix = glm::lookAt(position + (lightDir * 20.f / 2.f), -lightDir, glm::vec3(0,1,0));

glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix;
然而,这并不能真正让我明白我在追求什么。以下是阴影处理后的输出截图,以及在Photoshop中半自动转换为图像的阴影贴图:

渲染输出

阴影贴图

由于平行光是着色器中的唯一灯光,因此阴影贴图的渲染似乎非常接近正确,因为透视/方向大致匹配。然而,我不明白的是,为什么没有一个茶壶会给其他茶壶投下阴影

如果有人指点我可能做错了什么,我将不胜感激。我认为我的问题要么在于光空间矩阵的计算(我不确定如何正确地计算,给定一个移动的摄影机,以便视图中的内容将被更新),要么在于我确定延迟渲染器着色的纹理是否在阴影中。(FWIW,我从深度缓冲区确定世界位置,但我已经证明此计算是正确的。)


谢谢您的帮助。

调试阴影问题可能很棘手。让我们从以下几点开始:

  • 如果仔细观察渲染,实际上会在左上角的一个壶上看到阴影

  • 尝试旋转太阳,这通常有助于查看光线变换矩阵是否存在任何问题。从您的输出来看,太阳似乎非常水平,可能不会在此设置上投射阴影。(另一个角度可能会显示更多阴影)

  • 看起来好像您正在正确计算矩阵,但请尝试在glm::ortho(-10,10,-10,10,-10,20)中缩小最大深度,以紧密地适应场景。如果深度太大,将失去精度,阴影将出现瑕疵

  • 要进一步可视化问题的来源,请尝试从此处输出阴影贴图查找的结果:


  • 如果阴影贴图投影正确,则您知道在深度比较中存在问题。希望这有帮助

    调试阴影问题可能很棘手。让我们从以下几点开始:

  • 如果仔细观察渲染,实际上会在左上角的一个壶上看到阴影

  • 尝试旋转太阳,这通常有助于查看光线变换矩阵是否存在任何问题。从您的输出来看,太阳似乎非常水平,可能不会在此设置上投射阴影。(另一个角度可能会显示更多阴影)

  • 看起来好像您正在正确计算矩阵,但请尝试在glm::ortho(-10,10,-10,10,-10,20)中缩小最大深度,以紧密地适应场景。如果深度太大,将失去精度,阴影将出现瑕疵

  • 要进一步可视化问题的来源,请尝试从此处输出阴影贴图查找的结果:


  • 如果阴影贴图投影正确,则您知道在深度比较中存在问题。希望这有帮助

    谢谢-当我为阴影贴图分配深度纹理时,我向OpenGL传递了错误的值,这导致着色器在读取纹理时错误地解释了纹理。奇怪,但它现在可以工作了。谢谢-当我将深度纹理分配给阴影贴图时,我将错误的值传递给了OpenGL,这导致着色器在读取纹理时错误地解释了纹理。很奇怪,但现在可以用了。
    // lightSpaceMatrix is the same as above, FragWorldPos is world position of the texekl
    vec4 FragPosLightSpace = lightSpaceMatrix * vec4(FragWorldPos, 1.0f);
    
    // multiply non-ambient light values by ShadowCalculation(FragPosLightSpace)
    // ... do more stuff ...
    
    float ShadowCalculation(vec4 fragPosLightSpace) {
        // perform perspective divide
        vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
        // vec3 projCoords = fragPosLightSpace.xyz;
    
        // Transform to [0,1] range
        projCoords = projCoords * 0.5 + 0.5;
    
        // Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
        float closestDepth = texture(gSunShadowMap, projCoords.xy).r;
    
        // Get depth of current fragment from light's perspective
        float currentDepth = projCoords.z;
    
        // Check whether current frag pos is in shadow
        float bias = 0.005;
        float shadow = (currentDepth - bias) > closestDepth  ? 1.0 : 0.0;
    
        // Ensure that Z value is no larger than 1
        if(projCoords.z > 1.0) {
            shadow = 0.0;
        }
    
        return shadow;
    }
    
    closestDepth = texture(gSunShadowMap, projCoords.xy).r