c++ - OpenGL 阴影故障

标签 c++ opengl c++11 glsl shadow

问题

一段时间以来,我一直在尝试在 OpenGL 中实现阴影。我终于让它进入半工作状态,因为阴影出现但在奇怪的地方覆盖了场景 [即 - 它与光线无关] The issue at hand

为了进一步解释上面的 gif:当我将光源进一步远离场景(向左)时 - 阴影进一步延伸。为什么?如果有的话,它应该显示更多的场景。

更新 - 我搞砸了灯的位置,现在得到这个结果(令人困惑): enter image description here

深度图

这里是: The Shadow-map

代码

因为这是一个很难确定的问题 - 我将发布我在此应用程序中使用的大部分代码。

帧缓冲区和深度纹理 - 我首先需要的是一个帧缓冲区来记录所有绘制对象的深度值,然后我需要将这些值转储到深度纹理(阴影- map ):

// Create Framebuffer
FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);

// Create and Load Depth Texture
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

//Attach Texture To Framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

//Check for errors
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    Falcon::Debug::error("ShadowBuffer [Framebuffer] could not be initialized.");

渲染场景 - 首先我做阴影 channel ,它只运行一些基本的着色器并输出到帧缓冲区,然后我做第二次,实际绘制场景并执行 GLSL 的常规 channel 阴影贴图采样:

//Clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//Select Main Shader
normalShader->useShader();

//Bind + Update + Draw
    /* Render Shadows */
    shadowShader->useShader();
    glBindFramebuffer(GL_FRAMEBUFFER, Shadows::framebuffer());
        //Viewport
        glViewport(0,0,640,480);

        //GLM Matrix Definitions
        glm::mat4 shadow_matrix_view;
        glm::mat4 shadow_matrix_projection;

        //View And Projection Calculations
        shadow_matrix_view       =  glm::lookAt(glm::vec3(light.x,light.y,light.z), glm::vec3(0,0,0), glm::vec3(0,1,0));
        shadow_matrix_projection =  glm::perspective(45.0f, 1.0f, 0.1f, 1000.0f);

        //Calculate MVP(s)
        glm::mat4 shadow_depth_mvp = shadow_matrix_projection * shadow_matrix_view * glm::mat4(1.0);
        glm::mat4 shadow_depth_bias = glm::mat4(0.5,0,0,0,0,0.5,0,0,0,0,0.5,0,0.5,0.5,0.5,1) * shadow_depth_mvp;

        //Send Data To The GPU
        glUniformMatrix4fv(glGetUniformLocation(shadowShader->getShader(),"depth_matrix"), 1, GL_FALSE, &shadow_depth_mvp[0][0]);
        glUniformMatrix4fv(glGetUniformLocation(normalShader->getShader(),"depth_matrix_bias"), 1, GL_FALSE, &shadow_depth_bias[0][0]);

        renderScene();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    /* Clear */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* Shader */
    normalShader->useShader();

    /* Shadow-map */
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, Shadows::shadowmap());
    glUniform1f(glGetUniformLocation(normalShader->getShader(),"shadowMap"),0);

    /* Render Scene */
    glViewport(0,0,640,480);
    renderScene();

片段着色器 - 这是我计算要输出的最终颜色并进行深度纹理/阴影贴图采样的地方。这可能是我出错的地方:

//Shadows
uniform sampler2DShadow shadowMap;
in vec4 shadowCoord;

void main()
{
    //Lighting Calculations...
    //Shadow Sampling:
    float visibility = 1.0;
    if (texture(shadowMap, shadowCoord.xyz) < shadowCoord.z){
        visibility = 0.1;
    }

    //Final Output
    outColor = finalColor * visibility;
}

编辑

<1> AMD 硬件问题 - 也有人认为这可能是 GPU 的问题,但我觉得这很难相信,因为它是 Radeon HD 6670。是否值得放入 Nvidia 显卡来检验这一理论?

<2> 建议更改 - 我根据评论和答案提出了一些建议的更改:

首先,我将灯光的透视投影更改为正射投影,这为我提供了阴影贴图所需的精度,这样我现在就可以清楚地看到深度(即 -> 它不是全白的)。此外,它消除了透视划分的需要,所以我使用 3 维坐标来测试它。下面是截图: New Shadow-map

其次,我将我的纹理采样更改为:visibility = texture(shadowMap,shadowCoord.xyz); 现在总是返回 0,因此我看不到场景,因为它被认为完全阴影。

第三次也是最后一次,我按照建议将 GL_LEQUAL 换成了 GL_LESS,但没有发生任何变化。

最佳答案

您的着色器存在根本性错误:

uniform sampler2DShadow shadowMap; // NOTE: Shadow samplers perform comparison !!

...

if (texture(shadowMap, shadowCoord.xyz) < shadowCoord.z)

您启用了纹理比较与引用。这意味着 texture (...) 函数将比较第 3rd 纹理坐标,返回值将是测试函数的结果(在本例中为 GL_LEQUAL)。

换句话说,texture (...) 将通过比较外观返回 0.0(失败)或 1.0(通过) shadowCoord.xy 的深度增加到 shadowCoord.z 的值。你正在做这个测试两次。

考虑改用这个修改后的代码:

float visibility = texture(shadowMap, shadowCoord.xyz);

这不会产生您想要的结果,因为您的比较函数是 GL_LEQUAL,但这是一个开始。考虑将比较函数更改为 GL_LESS 以获得精确的功能匹配。

关于c++ - OpenGL 阴影故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25477382/

相关文章:

c++ - C++ 中作为右值的常量(11)

c++ - 为什么 shared_ptr 引用计数对象也需要跟踪指向该对象的 weak_ptr 上的数字?

c++ - 如何将对象类数据存储在数据库类数组中

c++ - 在构造函数成员初始化之前调用成员函数的语法

c++ - 通过鼠标点击绘制多边形

performance - 使用实例化渲染时,opengl 出现奇怪的减速

c++ - 带类的标签分发

c++ - 从 C++ 文件中读取,处理空白

c++ - Qt:为什么 connect() 只在主窗口类中起作用?

c++ - 我如何使用着色器将一个 3D 对象变形为另一个对象?