OpenGL Shadow Glitch

时间:2014-08-24 23:50:59

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

问题

我一直试图在OpenGL中实现阴影一段时间。我终于把它变成了一个半工作的状态,因为阴影出现但是在陌生的地方覆盖了场景[即 - 它与光线无关] The issue at hand

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

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

深度图

这是: The Shadow-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.");

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

//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;
}

编辑

&LT 1为卤素; AMD硬件问题 - 还有人认为这可能是GPU的一个问题,但我发现很难相信它是 Radeon HD 6670 。是否值得用一张Nvidia卡来测试这个理论?

&LT 2 - ;建议更改 - 我从评论和答案中做了一些建议的更改:

首先,我将光的透视投影改为正射投影,这使我在阴影贴图中获得了所需的精度,这样现在我可以清楚地看到深度(即 - &gt;它&#39; s不是全白)。此外,它消除了对透视分割的需要,因此我使用三维坐标来测试它。以下是截图: New Shadow-map

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

第三,也是最后,我从GL_LEQUALGL_LESS进行了交换,表明没有发生任何变化。

1 个答案:

答案 0 :(得分:2)

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

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

...

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

您启用了纹理比较与参考。这意味着3 rd 纹理坐标将由texture (...)函数进行比较,返回的值将是测试函数的结果(GL_LEQUAL情况)。

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

请考虑使用此更改的代码:

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

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