1
votes

I am having a strange problem in OpenGL. First some background: In my program I am implementing a bloom effect, using two textures with a full complement of mipmaps. Each mipmap level is attached to an FBO so that I can perform a 2-part gaussian blur on each level, before re-combining them to make the bloom. This part is all working nicely, and I could render a beautiful rotating glowing object.

The problem started when I tried to implement depth testing.

I added a depth map to the FBOs corresponding to level 0 of each texture. Then I enabled GL_DEPTH_TEST. As soon as I enabled GL_DEPTH_TEST, the screen started to flicker, and the object no longer rotated.

I have pared the code down to its simplest, and it seems to happen only when I render to an FBO with GL_DEPTH_TEST enabled. The problem doesn't happen if I render to the default framebuffer with GL_DEPTH_TEST enabled. The problem doesn't happen if I render to the FBO with GL_DEPTH_TEST disabled.

The code below is a simplified version of my code, just to illustrate the sequence of OpenGL calls that seems to re-create this problem. Please

Am I adding the depth buffer to the FBO correctly?

// Create a set of framebuffers, one for each mipmap level of a texture.
void FrameBuffer::Initialise(int xs, int ys)
{    
    xSizeTexture = PowerOfTwoAboveOrEqualTo(xs);
    ySizeTexture = PowerOfTwoAboveOrEqualTo(ys);
    numLevels = Log2(max(xSizeTexture, ySizeTexture));

    // Generate one FB for each texture level
    glGenFramebuffers(numLevels, frameBufferID);

    glGenTextures(1, &textureID);
    glBindTexture(  GL_TEXTURE_2D, textureID);
    glTexImage2D(   GL_TEXTURE_2D, 0, GL_RGB, xSizeTexture, ySizeTexture, 0, GL_RGB, GL_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numLevels-1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
    glGenerateMipmap(GL_TEXTURE_2D);

    // Bind each texture level to one FB
    for (int i = 0; i < numLevels; i++)
    {
        glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID[i]);
        glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, i);
    }

    attachment = GL_COLOR_ATTACHMENT0;
    glDrawBuffers(1, &attachment);

    // Add a depth buffer to the top FB
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID[0]);
    glGenRenderbuffers(1, &depthrenderbufferID);
    glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbufferID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, xSizeTexture, ySizeTexture);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbufferID);


    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        cout << "Failed to create frame buffer" << endl;
    else
        cout << "Created buffer OK" << endl;

    // Also initialise vertex array VAO
    // ...
}

void FrameBuffer::Use()
{
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID[0]);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void FrameBuffer::CopyToMain()
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, textureID);

    glViewport(0, 0, 1024, 1024);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);
}

void MainClass::Initialise()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    framebuffer.Initialise(1024, 1024);
}

void MainClass::Render()
{
    if (!initialised)
    {
        Initialise();
        initialised = true;
    }

    framebuffer.Use();
    glViewport(0, 0, 1024, 1024);
    glUseProgram(0);
    glEnable(GL_DEPTH_TEST);        // Causes problems
    //glDisable(GL_DEPTH_TEST);     // Works fine

    t += 0.05;
    glLoadIdentity();
    glRotatef(sin(t) * 10, 0, 0, 1);
    glLineWidth(2.0);

    glBegin(GL_LINE_LOOP);
        glColor3f(1.0, 0.1, 0.1); glVertex3f(-0.5, -0.5, 0.0);
        glColor3f(0.1, 1.0, 0.1); glVertex3f( 0.5, -0.5, 0.0);
        glColor3f(0.1, 0.1, 1.0); glVertex3f( 0.5,  0.5, 0.0);
        glColor3f(0.1, 0.1, 0.1); glVertex3f(-0.5,  0.5, 0.0);
    glEnd();

    framebuffer.CopyToMain();
}

I am getting no errors as reported by glGetError().

Please forgive the slightly pseudocode nature of the C++ code. It's just intended to illustrate the sequence of OpenGL calls made.

2
Only framebuffer frameBufferID[0] has a depth buffer attached, the other frame buffers have not depth buffer, so the depth test would work only, if you render to frameBufferID[0]. Where do you bind the different framebuffers and where do you render to it? The answer of @simpetra is also correct. Anyway, this is not Minimal, Complete, and Verifiable example.Rabbid76
@Rabbid76 - Understood. It's tricky trying to provide such a thing for an OpenGL problem like this. As I am currently using wxWidgets, and I presume nobody wants to see all the wx boilerplate, it would be a considerable effort to totally re-write all the code using a different, slimmer library.Rocketmagnet

2 Answers

3
votes

You forgot to include:

glDepthFunc(GL_LEQUAL);
1
votes

Did you try opengl Debug features?

Here you are binding a pointer (array name), not a gl name, should be frameBufferID[0], I suppose.

glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);