Stuck on nested FrameBufferObjects

Started by
2 comments, last by necreia 11 years, 1 month ago
I've been battling this long enough that I feel I must throw in the towel and ask for help. Ultimately, I'm trying to render to a FrameBufferObject, and then render that to another FrameBufferObject. Since I couldn't get it working in my game engine, I ran out to the net and cobbled together a really basic example in order to remove impacting variables. Even after this, I just can't get it. See here:
    uint16 mDisplayHeight = 1000;
    uint16 mDisplayWidth = 1600;
    int32 mVideoFlags;

    // Init SDL
    SDL_Init(SDL_INIT_VIDEO);
    mVideoFlags  = SDL_OPENGL;          // Use OpenGL in SDL
    mVideoFlags |= SDL_HWPALETTE;       // Hardware enabled palette
    const SDL_VideoInfo* sdlVideoInfo = SDL_GetVideoInfo();
    if (sdlVideoInfo->hw_available)
        mVideoFlags |= SDL_HWSURFACE;   // Hardware enabled surfaces
    else
        mVideoFlags |= SDL_SWSURFACE;   // Software enabled surfaces
    if (sdlVideoInfo->blit_hw)
        mVideoFlags |= SDL_HWACCEL;     // Hardware enabled blitting
    SDL_SetVideoMode(mDisplayWidth, mDisplayHeight, 32, mVideoFlags);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);

    // Initialize OpenGL
    glewInit();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);

    /** First FBO - The Render One **/
    uint32 mFinalFBOTexID = 0;
    uint32 mFinalFBOID = 0;
    glGenFramebuffers(1, &mFinalFBOID);
    glBindFramebuffer(GL_FRAMEBUFFER, mFinalFBOID);
    glGenTextures(1, &mFinalFBOTexID);
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFinalFBOTexID);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, mDisplayWidth,
                 mDisplayHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB,
                           mFinalFBOTexID, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    /****/

    /** Second FBO - Intermediate **/
    uint32 mSecondRenderTextureID = 0;
    uint32 mSecondRenderTextureFBO = 0;
    glGenFramebuffers(1, &mSecondRenderTextureFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, mSecondRenderTextureFBO);
    glGenTextures(1, &mSecondRenderTextureID);
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mSecondRenderTextureID);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, 300,
                 300, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB,
                           mSecondRenderTextureID, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    /****/

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, mDisplayWidth, mDisplayHeight, 0, -1, 1);
    glMatrixMode(GL_MODELVIEW);

    // Execution Loop
    while(true)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindFramebuffer(GL_FRAMEBUFFER, mFinalFBOID); // X1
        //glBindFramebuffer(GL_FRAMEBUFFER, mSecondRenderTextureFBO); //  X2

        // Draw a quad
        glDisable(GL_TEXTURE_RECTANGLE_ARB);
        glColor3f(1.0f, 1.0f, 0.0f);
        glBegin(GL_QUADS);
            glVertex2i(10, 10);
            glVertex2i(50, 10);
            glVertex2i(50, 50);
            glVertex2i(10, 50);
        glEnd();
        glEnable(GL_TEXTURE_RECTANGLE_ARB);

        /* X2
        glBindFramebuffer(GL_FRAMEBUFFER, mFinalFBOID);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mSecondRenderTextureID);

        glBegin(GL_QUADS);
            glTexCoord2i(0, 100);
            glVertex2i(0, 0);
            glTexCoord2i(100, 100);
            glVertex2i(100, 0);
            glTexCoord2i(100, 0);
            glVertex2i(100, 100);
            glTexCoord2i(0, 0);
            glVertex2i(0, 100);
        glEnd();
        */

        // Draw the 2D Layer on top
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glLoadIdentity();
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFinalFBOTexID);

        glBegin(GL_QUADS);
            glTexCoord2i(0, mDisplayHeight);
            glVertex2i(0, 0);
            glTexCoord2i(mDisplayWidth, mDisplayHeight);
            glVertex2i(mDisplayWidth, 0);
            glTexCoord2i(mDisplayWidth, 0);
            glVertex2i(mDisplayWidth, mDisplayHeight);
            glTexCoord2i(0, 0);
            glVertex2i(0, mDisplayHeight);
        glEnd();

        // Present the information
        SDL_GL_SwapBuffers();
    }

This code renders a yellow quad without any problems. But, if I uncomment the two X2 blocks and comment out the X1 block, I get a black screen. I can't seem to figure out how to paint to and render that second FBO.

Any advice? This is driving me bonkers. Am I approaching the solution wrong?
Advertisement

I don´t see why you disable GL_TEXTURE_RECTANGLE, just to enable it a few lines later, but that of course should not be the problem.

You should probably specify a viewport, but as you can see something in one case, that doesn´t seem to be the problem.

Try to disable blending.

I would recommend you to use a frame debugger, which exist for windows, linux, mac and most smartphones: https://www.opengl.org/wiki/Debugging_Tools

There you should be able to look at your target textures and find out where something goes wrong.

I disable GL_TEXTURE_RECTANGLE in order to unbind the current texture, so that the quad that is rendered is simply color splashed. I'm rendering 2D style, so Ortho should handle what I would have used viewport for.

I've not see that frame debugger before. Thanks. I'll take a look. When I try and dump the texture memory manually of that second texture, it doesn't appear that anything is being written there. Even more surprising, there are no GL_ERRORS! I've even adjusted the generated texture to be a power of two.

It has to be something simple... I just know it.

Edit: Oh, I had an extra disable. I see what you mean. Clipped it out.

In the end, it was the texture size issue. For any Googlers out there, this works:


    uint16 mDisplayHeight = 1000;
    uint16 mDisplayWidth = 1600;
    int32 mVideoFlags;

    // Init SDL
    SDL_Init(SDL_INIT_VIDEO);
    mVideoFlags  = SDL_OPENGL;          // Use OpenGL in SDL
    mVideoFlags |= SDL_HWPALETTE;       // Hardware enabled palette
    const SDL_VideoInfo* sdlVideoInfo = SDL_GetVideoInfo();
    if (sdlVideoInfo->hw_available)
        mVideoFlags |= SDL_HWSURFACE;   // Hardware enabled surfaces
    else
        mVideoFlags |= SDL_SWSURFACE;   // Software enabled surfaces
    if (sdlVideoInfo->blit_hw)
        mVideoFlags |= SDL_HWACCEL;     // Hardware enabled blitting
    SDL_SetVideoMode(mDisplayWidth, mDisplayHeight, 32, mVideoFlags);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);

    // Initialize OpenGL
    glewInit();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);

    // Create the frame buffers and textures
    unsigned int mFrameBufferTexIDs[2];
    unsigned int mFrameBufferObjectIDs[2];
    for (int i = 0; i < 2; i++)
    {
        glGenFramebuffers(1, &mFrameBufferObjectIDs[i]);
        glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectIDs[i]);
        glGenTextures(1, &mFrameBufferTexIDs[i]);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFrameBufferTexIDs[i]);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, mDisplayWidth, mDisplayHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, mFrameBufferTexIDs[i], 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, mDisplayWidth, mDisplayHeight, 0, -1, 1);
    glMatrixMode(GL_MODELVIEW);

    // Framebuffer and texture arrays are as follows:
    // 0 : Final output (what I want to present to the screen)
    // 1 : Intermediate output (what I want to render to and then render THAT to the screen)
    bool renderToIntermediateFBO = true;

    while(true)
    {
        if (renderToIntermediateFBO == false)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectIDs[0]);

            // Draw a quad with no texture
            glDisable(GL_TEXTURE_RECTANGLE_ARB);
            glColor3f(1.0f, 1.0f, 0.0f);
            glBegin(GL_QUADS);
                glVertex2i(10, 10);
                glVertex2i(50, 10);
                glVertex2i(50, 50);
                glVertex2i(10, 50);
            glEnd();
            glEnable(GL_TEXTURE_RECTANGLE_ARB);
        }
        else
        {
            glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectIDs[1]);

            // Draw a quad with no texture
            glDisable(GL_TEXTURE_RECTANGLE_ARB);
            glColor3f(1.0f, 1.0f, 0.0f);
            glBegin(GL_QUADS);
                glVertex2i(10, 10);
                glVertex2i(50, 10);
                glVertex2i(50, 50);
                glVertex2i(10, 50);
            glEnd();
            glEnable(GL_TEXTURE_RECTANGLE_ARB);

            // Draw the intermediate FBO onto the final FBO
            glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectIDs[0]);
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFrameBufferTexIDs[1]);
            glBegin(GL_QUADS);
                glTexCoord2i(0, mDisplayHeight);
                glVertex2i(0, 0);
                glTexCoord2i(mDisplayWidth, mDisplayHeight);
                glVertex2i(mDisplayWidth, 0);
                glTexCoord2i(mDisplayWidth, 0);
                glVertex2i(mDisplayWidth, mDisplayHeight);
                glTexCoord2i(0, 0);
                glVertex2i(0, mDisplayHeight);
            glEnd();

            // Draw another untextured quad on the final FBO
            glDisable(GL_TEXTURE_RECTANGLE_ARB);
            glColor3f(0.0f, 1.0f, 1.0f);
            glBegin(GL_QUADS);
                glVertex2i(20, 20);
                glVertex2i(60, 20);
                glVertex2i(60, 60);
                glVertex2i(20, 60);
            glEnd();
            glEnable(GL_TEXTURE_RECTANGLE_ARB);
        }

        // Present the final information to the screen
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glLoadIdentity();
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFrameBufferTexIDs[0]);
        glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_QUADS);
            glTexCoord2i(0, mDisplayHeight);
            glVertex2i(0, 0);
            glTexCoord2i(mDisplayWidth, mDisplayHeight);
            glVertex2i(mDisplayWidth, 0);
            glTexCoord2i(mDisplayWidth, 0);
            glVertex2i(mDisplayWidth, mDisplayHeight);
            glTexCoord2i(0, 0);
            glVertex2i(0, mDisplayHeight);
        glEnd();
        SDL_GL_SwapBuffers();
    }

This topic is closed to new replies.

Advertisement