2
votes

I've just implemented deferred rendering and am having trouble getting my skybox working. I try rendering my skybox at the very end of my rendering loop and all I get is a black screen. Here's the rendering loop:

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

The following is the skybox's render function

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

And here is the skybox's vertex shader:

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

The skybox's fragment shader just sets the output color to texture(cubeMap, TexCoord). As you can see from the vertex shader, I'm setting the position's z component to be w so that it will always have a depth of 1. I am also setting the depth function to be GL_LEQUAL so that it will fail the depth test. Should this not only draw the skybox in places where other objects weren't already drawn? Why does it result in a black screen?

I know I have set up the skybox correctly because if I just draw the skybox by itself it shows up just fine.

1
I guess your last sentence says it all. It works without drawing stuff previously. Either the previous draw calls are changing the GL state, such as enabling GL_DEPTH_TEST for the lighting pass, or drawing your geometry is changing the depth values everywhere. I haven't spotted anything obvious. I'd set gl_FragDepth rather than gl_Position.z because I would have assumed it'd mess with clipping, but if it works it works.jozxyqk
I don't know about the geometry changing the depth values everywhere but the lighting pass or any pass after the geometry pass does not change GL_DEPTH_TEST. I also tried setting gl_FragDepth but that still results in a black screen. I don't really know why it's not working. If I don't enable GL_DEPTH_TEST before rendering the skybox, it shows up but none of the other geometry shows because the skybox is on top of everything.theonewhoknocks
Oh, right. The thing about the black screen is pretty odd (I assumed you meant the background was black). If you draw something that overwrites previous values with black then something is indeed drawing. If you see sky without depth testing, I can only assume the sky overwrites the black geometry. Though TexCoord should ensure you don't get black assuming your texture isn't and is bound, unless the coord is zero (which would put the geometry behind the camera anyway). I'd try to narrow down what's causing the black. Maybe start by setting a constant colour in the fragment shader.jozxyqk
Even if I set the color to a constant color in the fragment shader it still results in a black screen. None of my geometry is black and the skybox is a bluish texture.theonewhoknocks
Well, I'm afraid I'm out of ideas. See if my answer helps, I've explained a little. If you do find the issue, I'd be interested to know what could have caused your problems!jozxyqk

1 Answers

2
votes

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

Since you're using double buffering, seeing different things must be due to a different frame being drawn. The depth buffer in the default framebuffer isn't being cleared, which I believe is the cause of the temporal instability at least.

In your case, you want the default depth buffer to be the same as the GBuffer when you draw the skybox. A quick way to achieve this is with glBlitFramebuffer, also avoiding the need to clear it:

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

Now to explain the black screen when the skybox fills the screen. Without the depth test, of course the skybox just draws. With the depth test, the skybox still draws on the first frame, but shortly after the second frame clears only the colour buffer. The depth buffer still contains stale skybox values so it does not get re-draw for this frame and you're left with black...

However your geometry pass draws without depth testing enabled, so this should still be visible even if the skybox isn't. Also this would only happen with GL_LESS and you have GL_LEQUAL. And you have glDepthMask false, which means nothing should write to the default depth buffer in your code. This points to the depth buffer containing other values, perhaps uninitialized, but in my experience it's initially zero. Also this still happens when the skybox doesn't fill the screen, drawn as a cube away from the camera, which blows away that argument. Now, perhaps if the geometry failed to draw in the second frame that would explain it. For that matter blatant driver bugs would too, but I'm not seeing any problems in the given code.

TLDR: Many unexplained things, so **I tried it myself and can't reproduce your problem...

Here's a quick example based on your code and it works fine for me...

(green sphere is the geometry, red cube is the skybox)

gl_Position = pos:
enter image description here

Note the yellow from additive blending even if the skybox is drawn over the top. I would have thought you'd be seeing this too.

gl_Position = pos.xyww:
enter image description here

Now for the code...

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