c++ - 延迟渲染 Skybox OpenGL

标签 c++ opengl glsl deferred-rendering skybox

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

    //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, ...);

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

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

TLDR:许多无法解释的事情,所以**我自己尝试过,但无法重现您的问题...

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

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

gl_Position = pos:
enter image description here

请注意,即使天空盒绘制在顶部,加法混合也会产生黄色。我以为你也会看到这个。

gl_Position = pos.xyww:
enter image description here

现在是代码...

//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();

关于c++ - 延迟渲染 Skybox OpenGL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29321761/

相关文章:

java - 天空盒不显示纹理

GLSL 2.0 颜色和纹理

c++ - 制作shader将vertexArray作为canvas而不是window

c++ - Visual Studio 2015 - 看不到现有项目的代码

c++ - 如何轻松地展开一排 Qt 小部件,使它们始终均匀分布?

c++ - mOffsetMatrix 在 Assimp 中实际上做了什么?

opengl - 给定一个投影矩阵,如何在 OpenGL 中获得视角?

opengl - 骨骼动画顶点着色器的性能问题

c++ - C++中返回指针的函数

c++ - 是否可以在 C++ 中的表达式中定义变量?