Search code examples
c++openglfragment-shaderframebufferglreadpixels

Fragment Shader Multiple Output and Reading from FrameBuffer Object Issue


I have 2 outputs in fragment shader first one's output color (RGBA) and the second one's is a number which will serve as an id but I try to read it from frameBuffer it always returns 0. The way how I read from FBO:

int FrameBuffer::ReadPixels(float x,float y, int attachment)
{
    GLerror(glReadBuffer(GL_COLOR_ATTACHMENT0+attachment));
    int value;
    GLerror(glReadPixels(x,y, 1, 1, GL_RED_INTEGER, GL_INT, &value));
    return value;
}

And this method called in loop like:

        FBO.Bind();
    renderer.Clear();
    renderer.Draw(Circle_VAO, Circle_Shader, Circle_IB);
    renderer.Draw(Quad_VAO, Quad_Shader, Quad_IB);
    std::cout << FBO.ReadPixels(450,360,1) << std::endl;
    FBO.Unbind();

These are the FBO attachments:

GLerror(glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID));

    
    GLerror(glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererColorAttachments[0]));
    GLerror(glBindTexture(GL_TEXTURE_2D, m_RendererColorAttachments[0]));
    GLerror(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1820.0, 720.0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
    GLerror(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D, m_RendererColorAttachments[0], 0));
    GLerror(glBindTexture(GL_TEXTURE_2D, 0));

    GLerror(glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererColorAttachments[1]));
    GLerror(glBindTexture(GL_TEXTURE_2D, m_RendererColorAttachments[1]));
    GLerror(glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 1820.0, 720.0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
    GLerror(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
    GLerror(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_RendererColorAttachments[1], 0));
    GLerror(glBindTexture(GL_TEXTURE_2D, 0));
    
    GLerror(glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererDepthID));
    GLerror(glBindTexture(GL_TEXTURE_2D, m_RendererDepthID));
    GLerror(glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 1820.0, 720.0));
    GLerror(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_RendererDepthID, 0));
    GLerror(glBindTexture(GL_TEXTURE_2D, 0));
    auto fboS = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (fboS != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "FRAMEBUFFER INCOMPLETE  " << fboS << std::endl;
    GLerror(glBindFramebuffer(GL_FRAMEBUFFER, 0));

Fragment and vertex Shader:

    #shader vertex
    #version 460 core
        layout(location=0) in vec3 position;
        layout(location=1) in vec3 colors;
        layout(location=2) in vec2 texCoords;
        layout(location=3) in int a_ObjectID;
        uniform mat4 u_MVP;
        out vec3 v_Colors;
        out flat int v_ObjectID;
        void main()
        {
            gl_Position=u_MVP*vec4(position,1.0);
            v_ObjectID = a_ObjectID;
            v_Colors=colors;
        };

    #shader fragment
    #version 460 core

        layout(location=0) out vec4 color;
        layout(location=1) out int o_ObjectID;
        in vec3 v_Colors;

        in flat int v_ObjectID;
        void main()
        {
            color=vec4(v_Colors,1.0);
            o_ObjectID = 50;
        };

I have fragment and vertex shader for Quads and Circles (I sent shaders for circles)

I want to read value :50 (because I set second output as 50 as you can see above) from FBO.ReadPixels(...) for specified pixel but it returns 0 on the other hand the firs output of fragment shader works as ı expected and shows colors.If ı Set o_ObjectID as the first output and make the m_RendererColorAttachment[1] attached to GL_COLOR_ATTACHMENT0 and try to read it from there function returns the value 50. (By the way that specified Xpos,Ypos (450,360) are in the range of circle's coordinates.) So ı searched the Internet to find how to solve it. I found related topics but ı still couldn't figured it out.


Solution

  • In addition to setting up the FBO, you also need to specify which buffers are mapped to which output of the fragment shader. This is done by calling glDrawBuffers (or glNamedFramebufferDrawBuffers) and passing an array that specifies for each fragment shader output location which attachment to use.

    For your case, the following code should work

    GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
    glDrawBuffers(2, attachments);