glReadPixels takes viewport and not binded framebuffer on Ubuntu

  c++, framebuffer, glreadpixels, opengl, ubuntu

I have a program that displays 3D models and I need to take screenshots. It works fine on Windows but not on Ubuntu.

When I take a screenshot from Windows, I get an image of the size of my camera filled by the rendered model.

When I take a screenshot from Ubuntu, I get an image of the size of my camera filled with what’s rendered on my viewport and other pixels are filled by random values.

Image rendered on Ubuntu

Framebuffer creation code :

void OpenGLEngine::createFrameBuffer()
{
    if (frameBuffers.size() > 0)
        deleteFrameBuffer();

    for (int i = 0; i < system; i++)
    {
        FrameBuffer* frameBuffer = new FrameBuffer;

        /* Frame buffer Initialisation : Texture container */
        if (!glIsFramebuffer(frameBuffer->renderFramebufferId))  glGenFramebuffers(1, &frameBuffer->renderFramebufferId);
        glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->renderFramebufferId);

        if (antialiasing)
        {
            glEnable(GL_MULTISAMPLE);

            /* Multisample Texture Initialisation: output shader color container */
            if (!glIsTexture(frameBuffer->renderTextureId)) glGenTextures(1, &frameBuffer->renderTextureId);
            glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, frameBuffer->renderTextureId);
            glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, antialiasingSamples, GL_RGBA8, cameras[i]->getWidth(), cameras[i]->getHeight(), true);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, frameBuffer->renderTextureId, 0);

            /* Depth Buffer Initialisation */
            if (!glIsRenderbuffer(frameBuffer->depthBufferId)) glGenRenderbuffers(1, &frameBuffer->depthBufferId);
            glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->depthBufferId);
            glRenderbufferStorageMultisample(GL_RENDERBUFFER, antialiasingSamples, GL_DEPTH_COMPONENT, cameras[i]->getWidth(), cameras[i]->getHeight());
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->depthBufferId);

            /* Resolve multisample Texture to normal Texture */
            if (!glIsFramebuffer(frameBuffer->resolveFramebufferId)) glGenFramebuffers(1, &frameBuffer->resolveFramebufferId);
            glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->resolveFramebufferId);
        }
        else
        {
            glDisable(GL_MULTISAMPLE);

            /* Depth Buffer Initialisation */
            if (!glIsRenderbuffer(frameBuffer->depthBufferId)) glGenRenderbuffers(1, &frameBuffer->depthBufferId);
            glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->depthBufferId);
            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, cameras[i]->getWidth(), cameras[i]->getHeight());
            glBindRenderbuffer(GL_RENDERBUFFER, 0);
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->depthBufferId);
        }

        /* Final render Texture Initialisation: output shader color container */
        if (!glIsTexture(cameras[i]->id)) glGenTextures(1, &cameras[i]->id);
        glBindTexture(GL_TEXTURE_2D, cameras[i]->id);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cameras[i]->getWidth(), cameras[i]->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
        glBindTexture(GL_TEXTURE_2D, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cameras[i]->id, 0);

        if (glGetError() != GL_NO_ERROR) throw(e3mException(11102, "frame buffer did not get create properly"));

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        frameBuffers.push_back(frameBuffer);
    }
}

Taking screenshots (call of the rendererfunction) :

glBindFramebuffer(GL_FRAMEBUFFER, 0);

glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffers[i]->renderFramebufferId);
{
    if (antialiasing)
    {
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffers[i]->resolveFramebufferId);

        glBlitFramebuffer(0, 0, cameras[i]->getWidth(), cameras[i]->getHeight(), 0, 0, cameras[i]->getWidth(), cameras[i]->getHeight(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glBlitFramebuffer(0, 0, cameras[i]->getWidth(), cameras[i]->getHeight(), 0, 0, cameras[i]->getWidth(), cameras[i]->getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);

        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
        glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffers[i]->resolveFramebufferId);
    }

    if (rendererFunction != nullptr) rendererFunction(); //It calls getColorImage if a screenshot is asked
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

Renderer function :

void OpenGLViewer::getColorImage(vpImage<vpRGBa> &image, bool movie)
{
    static bool screenshoot = false;

    if (!screenshoot && !movie)
    {
        engine->setRendererFunction(std::bind(&OpenGLViewer::getColorImage, this, std::ref(image), false));
        screenshoot = true;
        while (screenshoot) qApp->processEvents();
        engine->setRendererFunction(nullptr);
    }
    else
    {
        const int buffSize = (COLOR_SIZE+1) * engine->getWidth() *  engine->getHeight();
        unsigned char* pixels = new unsigned char[buffSize];

        glReadPixels(0, 0, engine->getWidth(), engine->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels);

        int index = 0;
        for (int i = image.getHeight() - 1; i >= 0; i--) // for horizontal flip
        {
            for (int j = 0; j < image.getWidth(); j++)
            {
                image[i][j].R = pixels[index++];
                image[i][j].G = pixels[index++];
                image[i][j].B = pixels[index++];
                image[i][j].A = pixels[index++];
            }
        }
        delete[] pixels;

        screenshoot = false;
    }
}

Source: Windows Questions C++

LEAVE A COMMENT