This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Multi Render Target (MRT) with FBO

I am trying to implement the multi render target effect of open gl 3 using a single FBO with multiple color attachment points. I am attaching 4 textures(loaded with images) to 4 color attachment points of the FBO. After this ia m trying to blit from the framebuffer. However, i cannot see any output. Could anyone point out the error in my code.

This is an example to demonstrate Multiple Render Targets and framebuffer blits.

    First, we will render a quad that outputs four textures

    per fragment using MRTs.

    Then, we will copy the four color buffers into four screen quadrants

    using framebuffer blits.

code :

#include <EGL/egl.h>

#include <GLES3/gl3.h>

#include <stdlib.h>

#include <math.h>

#include <time.h>

#include <unistd.h>

#include <signal.h>

#include "MultiRenderTarget.h"

#include "imageload.h"

#define mMAXFC 500

extern EGLDisplay    sEGLDisplay;

extern EGLSurface    sEGLSurface;

static const char* samplerNames1[4]=

{

    "tex1",

    "tex2",

    "tex3",

    "tex4",

};

struct texImage

{

    char *fileName;

    GLenum imgFormat;

    const char*  nameOfImageIneternalformat;

};

char *bmp_texpath[100] = {

   

    (char*)"./assets/Raw1.bmp",

    (char*)"./assets/Raw2.bmp",

    (char*)"./assets/Raw3.bmp",

    (char*)"./assets/Raw4.bmp",

    };

   

    GLfloat texcoords_bmp1[] =

    {

        0, 0,

        0, 1,

        1, 1,

        1, 0

    };

   

int width=res.h_res,height=res.v_res;

GLuint VSObject,FSObject;

GLuint ProgramObject;

GLuint mfbo;

GLuint colorTexId[4];

GLsizei textureWidth =res.h_res;

GLsizei textureHeight = res.v_res;

int MRT_bDone = 0;

int mframeCount = 0;

ImageData img[5] ;

void MRT_signalHandler (int sig)

{

    switch (sig)

        {

            case SIGINT:

            case SIGTERM:

                GTS_INFO("Ctrl+c pressed\n");

                MRT_bDone = 1;

            default:

                break;

    }

}

const GLenum attachments[4] =

{

    GL_COLOR_ATTACHMENT0,

    GL_COLOR_ATTACHMENT1,

    GL_COLOR_ATTACHMENT2,

    GL_COLOR_ATTACHMENT3

};

  

int InitFBO ( )

{

    int i;

    GLint defaultFramebuffer = 0;

    glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

       glGenFramebuffers ( 1, &mfbo );

       glBindFramebuffer ( GL_FRAMEBUFFER, mfbo );

  

    glGenTextures ( 4, &colorTexId[0] );

   

    for (i = 0; i < 4; ++i)

       {

          GetImageFromBMP(&img[index],bmp_texpath[index]);

          if(img->imagedata != NULL)

          {

           GL_CHECK(glActiveTexture(GL_TEXTURE0 + i));

          glBindTexture ( GL_TEXTURE_2D, colorTexId[i] );

          glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA,

                         img->OriginalImageWidth, img->OriginalImageHeight,

                         0, GL_RGBA, GL_UNSIGNED_BYTE, img[i].imagedata );

          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

          glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );

          glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

          glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER, attachments[i],

                               GL_TEXTURE_2D, colorTexId[i], 0 );

          }

    }

       glDrawBuffers ( 4, attachments );

       if ( GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus ( GL_FRAMEBUFFER ) )

       {

              return false;

       }

       // Restore the original framebuffer

       glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );

       return true;

}

GLfloat vVertices[] = { -1.0f,  1.0f, 0.0f,

                            -1.0f, -1.0f, 0.0f,

                             1.0f, -1.0f, 0.0f,

                             1.0f,  1.0f, 0.0f,

                              };

       GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

   

   

void DrawGeometry ( )

{

   

       // Set the viewport

       glViewport ( 0, 0, width,height );

       // Clear the color buffer

       glClear ( GL_COLOR_BUFFER_BIT );

      

    glUseProgram ( ProgramObject );

      

    glBindFramebuffer ( GL_FRAMEBUFFER, mfbo );

    //glDrawBuffers(4,attachments);

    for(i=0; i<4; i++)

    {

        glDrawBuffers(1,attachments[i]);

    //for(i=0; i<4; i++)

        //{

        GL_CHECK(glActiveTexture(GL_TEXTURE0 + i));

        GL_CHECK(glBindTexture(GL_TEXTURE_2D,colorTexId[i]));

        //}

    glVertexAttribPointer ( 0, 3, GL_FLOAT,

                               GL_FALSE, 3 * sizeof ( GLfloat ), vVertices );

    GL_CHECK(glGenBuffers(1, texbuf));

    GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, texbuf));

    GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords_bmp1), texcoords_bmp1, GL_STATIC_DRAW));

    GLuint textureCoordinateLocation1 = GL_CHECK(glGetAttribLocation (uiProgramObject, "attributeTextureCoordinate1"));

    GL_CHECK(glEnableVertexAttribArray(textureCoordinateLocation1));

   

    //for(i=0; i<4; i++)

        //{

        GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, texbuf));

        GL_CHECK(glVertexAttribPointer(textureCoordinateLocation1, 2, GL_FLOAT, GL_FALSE, 0, 0));

        GL_CHECK(glBindTexture(GL_TEXTURE_2D, colorTexId[i]));

    //}

        //for(i=0; i<4; i++)

        //{

        GL_CHECK(glUniform1i(glGetUniformLocation(ProgramObject, samplerNames1[i]),i));

        //}

   

       

   

   

   

       // Load the vertex position

  

   

       glEnableVertexAttribArray ( 0 );

       // Draw a quad

       glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );

    }

}

///

// Copy MRT output buffers to screen

//

void BlitTextures ( )

{

       int index= 0;

       glBindFramebuffer ( GL_READ_FRAMEBUFFER, mfbo );

      

    while( mframeCount < mMAXFC && !MRT_bDone){

      

           // Copy the output red buffer to lower left quadrant

           glReadBuffer ( attachments[(index+0)%4] );

           glBlitFramebuffer ( 0, 0, textureWidth, textureHeight,

                               0, 0, width/2, height/2,

                               GL_COLOR_BUFFER_BIT, GL_LINEAR );

                      

           // Copy the output green buffer to lower right quadrant

           glReadBuffer ( attachments[(index+1)%4] );

           glBlitFramebuffer ( 0, 0, textureWidth, textureHeight,

                               width/2, 0, width, height/2,

                               GL_COLOR_BUFFER_BIT, GL_LINEAR );

           // Copy the output blue buffer to upper left quadrant

           glReadBuffer ( attachments[(index+2)%4] );

           glBlitFramebuffer ( 0, 0, textureWidth, textureHeight,

                               width/2, height/2, width, height,

                               GL_COLOR_BUFFER_BIT, GL_LINEAR );

      

           // Copy the output gray buffer to upper right quadrant

           glReadBuffer ( attachments[(index+3)%4] );

           glBlitFramebuffer ( 0, 0, textureWidth, textureHeight,

                               0, height/2, width/2, height,

                               GL_COLOR_BUFFER_BIT, GL_LINEAR );

        GTS_INFO("Frame Count ----> %d\n",mframeCount + 1);

                   eglSwapBuffers(sEGLDisplay,sEGLSurface);

        mframeCount ++;

                  usleep(200000);

                        

            index+=1;

            if(index>=4)

            index=0;

    }

}

///

// Render to MRTs and screen

//

GLuint vb;

void Draw ( )

{

  

    static const GLfloat buffer_data[] = {

   -1.0f, -1.0f, 0.0f,

   1.0f, -1.0f, 0.0f,

   0.0f,  1.0f, 0.0f,

    };

    GLint defaultFramebuffer = 0;

    glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

   

    //GLuint texID = glGetUniformLocation(quad_programID, "renderedTexture1");

   

    // FIRST: use MRTs to output four colors to four buffers

    glBindFramebuffer ( GL_FRAMEBUFFER, mfbo );

    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    //glDrawBuffers ( 4, attachments );

    //glDrawBuffers ( 1, attachments[0] );

    //for triangle

/*    glGenBuffers(1, &vb);

    glBindBuffer(GL_ARRAY_BUFFER, vb);

    glBufferData(GL_ARRAY_BUFFER, sizeof(buffer_data), buffer_data, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, vb);

    glVertexAttribPointer( 0,3,GL_FLOAT,GL_FALSE,0,(void*)0); 

      glDrawArrays(GL_TRIANGLES, 0, 3);

   

    glDrawBuffers ( 1, attachments[1] );

   

    GLuint texID1 = glGetUniformLocation(quad_programID, "renderedTexture2");

    //for square

    GLfloat vertices[] = {-1, -1, 0,

                          -1,  1, 0,

                           1,  1, 0,

                           1, -1, 0};

    GLubyte indices[] = {0,1,2,

                         0,2,3};

   

    glGenBuffers(1, &vb1);

    glBindBuffer(GL_ARRAY_BUFFER, vb1);

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, vb1);

    glVertexAttribPointer(0,3, GL_FLOAT,GL_FALSE 0, (void*)0);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);

   

   

        glViewport ( 0, 0, width,height );

       // Clear the color buffer

       glClear ( GL_COLOR_BUFFER_BIT );

      

    glUseProgram ( ProgramObject );

    */

    DrawGeometry ( );

    // Restore the default framebuffer

    glBindFramebuffer ( GL_DRAW_FRAMEBUFFER, defaultFramebuffer );

    BlitTextures ( );

}

int MultiRenderTarget ()

{

    signal (SIGINT, MRT_signalHandler);

        signal (SIGTERM, MRT_signalHandler);

   

    if(processShader(&VSObject, (char *)VERT_FILE_IR, GL_VERTEX_SHADER) == EXIT_FAILURE)

        return EXIT_FAILURE;

    if(processShader(&FSObject, (char *)FRAG_FILE_IR, GL_FRAGMENT_SHADER) == EXIT_FAILURE)

        return EXIT_FAILURE;

    ProgramObject = GL_CHECK(glCreateProgram());

    GL_CHECK(glAttachShader(ProgramObject, VSObject));

    GL_CHECK(glAttachShader(ProgramObject, FSObject));

    GL_CHECK(glLinkProgram(ProgramObject));

       

    InitFBO ();

    glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );

    Draw();

//    ShutDown();

    GL_CHECK(glUseProgram(0));

    GL_CHECK(glDeleteShader(VSObject));

    GL_CHECK(glDeleteShader(FSObject));

    GL_CHECK(glDeleteProgram(ProgramObject));

    MRT_bDone = 0;

    return 0;

}

Vertex Shader:

#version 300 es

layout(location = 0) in vec4 a_position;

in        vec2 attributeTextureCoordinate1;

out vec2 varyingTextureCoordinate1;

void main()

{

  varyingTextureCoordinate1 = attributeTextureCoordinate1;

  gl_Position = a_position;

}

fragment Shader:

#version 300 es

precision mediump float;

uniform sampler2D tex1;

uniform sampler2D tex2;

uniform sampler2D tex3;

uniform sampler2D tex4;

in      vec2      varyingTextureCoordinate1;

layout(location = 0) out vec4 fragData0;

layout(location = 1) out vec4 fragData1;

layout(location = 2) out vec4 fragData2;

layout(location = 3) out vec4 fragData3;

void main()

{

   fragData0 = texture(tex1,varyingTextureCoordinate1);

   fragData1 = texture(tex2,varyingTextureCoordinate1);

   fragData2 = texture(tex3,varyingTextureCoordinate1);

   fragData3 = texture(tex4,varyingTextureCoordinate1);

}

  • I found your code a little hard to follow due to the large sections and loops commented out, but the first thing I notice is the odd behaviour of your DrawGeometries method, which seems to have a for loop whereby each iteration apparently binds a single texture, a single buffer and a single attribute then commits one draw, whereas I'd imagine what you wanted to do was bind your various attributes textures and buffers and then draw once.

    I think perhaps it would help you to start a little smaller, get this working with a single render to texture, then step it up to a pair of render targets, then see about putting it in indexed loops.