We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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 );
//glDrawBuffers(4,attachments);
for(i=0; i<4; i++)
glDrawBuffers(1,attachments[i]);
//for(i=0; i<4; 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));
GL_CHECK(glVertexAttribPointer(textureCoordinateLocation1, 2, GL_FLOAT, GL_FALSE, 0, 0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, colorTexId[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] );
width/2, 0, width, height/2,
// Copy the output blue buffer to upper left quadrant
glReadBuffer ( attachments[(index+2)%4] );
width/2, height/2, width, height,
// Copy the output gray buffer to upper right quadrant
glReadBuffer ( attachments[(index+3)%4] );
0, height/2, width/2, height,
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[] = {
0.0f, 1.0f, 0.0f,
//GLuint texID = glGetUniformLocation(quad_programID, "renderedTexture1");
// FIRST: use MRTs to output four colors to four buffers
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);
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);
glVertexAttribPointer(0,3, GL_FLOAT,GL_FALSE 0, (void*)0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
*/
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)
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:
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;
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.