延迟渲染 Skybox OpenGL

Deferred Rendering Skybox OpenGL

我刚刚实施了延迟渲染,但我无法让我的天空盒正常工作。我尝试在渲染循环的最后渲染我的天空盒,但我得到的只是一个黑屏。这是渲染循环:

    //binds the fbo
    gBuffer.Bind();

    //the shader that writes info to gbuffer
    geometryPass.Bind();

    glDepthMask(GL_TRUE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);

    //draw geometry
    geometryPass.SetUniform("model", transform.GetModel());
    geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform.GetModel());

    mesh3.Draw();

    geometryPass.SetUniform("model", transform2.GetModel());
    geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform2.GetModel());
    sphere.Draw();

    glDepthMask(GL_FALSE);
    glDisable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendEquation(GL_FUNC_ADD);
    glBlendFunc(GL_ONE, GL_ONE);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    //shader that calculates lighting
    pointLightPass.Bind();
    pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());

    for (int i = 0; i < 2; i++)
    {
        pointLightPass.SetUniformPointLight("light", pointLights[i]);
        pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
        //skybox.GetCubeMap()->Bind(9);
        quad.Draw();
    }

    //draw skybox
    glEnable(GL_DEPTH_TEST);
    skybox.Render(camera);

    window.Update();
    window.SwapBuffers();

下面是天空盒的渲染函数

glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);

m_transform.SetPosition(camera.GetTransform().GetPosition());
m_shader->Bind();

m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
m_shader->SetUniform("cubeMap", 0);

m_cubeMap->Bind(0);
m_cubeMesh->Draw();

glDepthFunc(GL_LESS);
glCullFace(GL_BACK);

这里是天空盒的顶点着色器:

layout (location = 0) in vec3 position;

out vec3 TexCoord;

uniform mat4 mvp;

void main()
{
    vec4 pos = mvp * vec4(position, 1.0);
    gl_Position = pos.xyww;
    TexCoord = position;
}

天空盒的片段着色器只是将输出颜色设置为texture(cubeMap, TexCoord)。 正如您从顶点着色器中看到的那样,我将位置的 z 分量设置为 w,这样它的深度将始终为 1。我还将深度函数设置为 GL_LEQUAL 这样它就无法通过深度测试。这不应该只在其他对象尚未绘制的地方绘制天空盒吗?为什么会导致黑屏?

我知道我已经正确设置了天空盒,因为如果我自己绘制天空盒,它就会显示得很好。

I can briefly see for a split second the geometry that should be drawn before the skybox is drawn on top of everything.

由于您使用的是双缓冲,看到不同的东西一定是由于绘制了不同的帧。默认帧缓冲区中的深度缓冲区未被清除,我认为这至少是时间不稳定的原因。

在您的情况下,您希望默认深度缓冲区与绘制天空盒时的 GBuffer 相同。实现此目的的一种快速方法是使用 glBlitFramebuffer,同时避免清除它的需要:

glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(..., GL_DEPTH_BUFFER_BIT, ...);

现在解释天空盒填满屏幕时的黑屏。没有深度测试,天空盒当然只是绘制。通过深度测试,天空盒仍然在第一帧上绘制,但在第二帧后不久仅清除颜色缓冲区。深度缓冲区仍然包含陈旧的天空盒值,因此它不会为这一帧重新绘制,你只剩下黑色...

然而,您的几何通道在未启用深度测试的情况下绘制,因此即使天空盒未启用,它也应该仍然可见。此外,这只会发生在 GL_LESS 并且您有 GL_LEQUAL 的情况下。 你有 glDepthMask false,这意味着你的代码中不应该写入默认深度缓冲区。这指向包含其他值的深度缓冲区,可能未初始化,但根据我的经验,它最初为零。当天空盒没有填满屏幕时,这种情况仍然会发生,绘制为远离相机的立方体,这消除了那个论点。现在,也许如果几何图形未能在第二帧中绘制就可以解释它。就此而言,明显的驱动程序错误也会,但我在给定代码中没有看到任何问题。

TLDR:很多无法解释的东西,所以**我自己试了一下,无法重现你的问题...

这是一个基于您的代码的简单示例,对我来说效果很好...

(绿色球体是几何体,红色立方体是天空盒)

gl_Position = pos:

请注意加色混合中的黄色,即使天空盒绘制在顶部也是如此。我还以为你也会看到这个。

gl_Position = pos.xyww:

现在是代码...

//I haven't enabled back face culling, but that shouldn't affect anything

//binds the fbo
fbo.bind();

//the shader that writes info to gbuffer
//geometryPass.Bind(); //fixed pipeline for now

glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);

glColor3f(0,1,0);
fly.uploadCamera(); //glLoadMatrixf
sphere.draw();

glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);

fbo.unbind(); //glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);

//shader that calculates lighting
drawtex.use();
//pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());
drawtex.set("tex", *(Texture2D*)fbo.colour[0]);

for (int i = 0; i < 2; i++)
{
    //pointLightPass.SetUniformPointLight("light", pointLights[i]);
    //pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
    //skybox.GetCubeMap()->Bind(9);
    drawtex.set("modelviewMat", mat44::identity());
    quad.draw();
}

drawtex.unuse();

//draw skybox
glEnable(GL_DEPTH_TEST);

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fbo.size.x, fbo.size.y, 0, 0, fbo.size.x, fbo.size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

//glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);

//m_transform.SetPosition(camera.GetTransform().GetPosition());
skybox.use();

skybox.set("mvp", fly.camera.getProjection() * fly.camera.getInverse() * mat44::translate(1,0,0));
//m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
//m_shader->SetUniform("cubeMap", 0);

//m_cubeMap->Bind(0);
cube.draw();
skybox.unuse();

glDepthFunc(GL_LESS);
//glCullFace(GL_BACK);

//window.Update();
//window.SwapBuffers();