[MRT] frame buffer object : target rendering

Hi everyboby !

I have a problem with my code.
I want to use FBOs to send the rendering of my video to another fragment shader.
Here is my code.


#include "utils.h"

int width=512;
int height=512;

// perspective projection
bool perspective = false;

// geometry
#define _NBFACES 2 // 2 triangles

////////////////////////////////////////
// geometrical data
float points[_NBFACES * 3 * 3] = {
  0.0f,         (float)height,  0.0f, //1st triangle
  (float)width, 0.0f,  0.0f,
  0.0f,         0.0f,  0.0f,
  0.0f,         (float)height,  -0.0f, //2nd triangle
  (float)width, (float)height,  -0.0f, 
  (float)width,  0.0f,  -0.0f
};
float texCoords[_NBFACES * 3 * 2] = {
  0.0f,         (float)height, //1st triangle
  (float)width, 0.0f,
  0.0f,         0.0f,
  0.0f,         (float)height, //2nd triangle
  (float)width, (float)height, 
  (float)width,  0.0f
};

// texture
cv::Mat image[2];
GLuint textureID[2];

// multipass
GLuint frameBufferId[4];
GLuint frameBufferTextureId[4];
GLuint drawBuffers[16] = {
	GL_COLOR_ATTACHMENT0,
	GL_COLOR_ATTACHMENT1,
	GL_COLOR_ATTACHMENT2,
	GL_COLOR_ATTACHMENT3,
	GL_COLOR_ATTACHMENT4,
	GL_COLOR_ATTACHMENT5,
	GL_COLOR_ATTACHMENT6,
	GL_COLOR_ATTACHMENT7,
};

// shader variable pointers
GLint uniform_image_model;
GLint uniform_image_view;
GLint uniform_image_proj;
GLint uniform_video_texture;
//GLint uniform_mask_texture;
GLint uniform_nbFrames;

// shader variable pointers multipass
GLint uniform_writeFBO1_model;
GLint uniform_writeFBO1_view;
GLint uniform_writeFBO1_proj;
GLint uniform_writeFBO1_texture;
GLint uniform_writeFBO2_model;
GLint uniform_writeFBO2_view;
GLint uniform_writeFBO2_proj;
GLint uniform_writeFBO2_texture;
GLint uniform_writeFBO3_model;
GLint uniform_writeFBO3_view;
GLint uniform_writeFBO3_proj;
GLint uniform_writeFBO3_texture;
GLint uniform_writeFBO4_model;
GLint uniform_writeFBO4_view;
GLint uniform_writeFBO4_proj;
GLint uniform_writeFBO4_texture;

GLint uniform_writeFB04_texture_transfer;

GLint uniform_texture_FBO1;
GLint uniform_texture_FBO2;
GLint uniform_texture_FBO3;
GLint uniform_texture_FBO4;

GLint uniform_readFBO_model;
GLint uniform_readFBO_view;
GLint uniform_readFBO_proj;
GLint uniform_readFBO_video_texture;


/////////////////////////////////////////////
// FBO alloc 
bool FBOInit( void ) {
  int maxbuffers;
  glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxbuffers);
  printf("Max attachments %d
",maxbuffers);

  glGenFramebuffers( 4, frameBufferId );

  // attaching images to FBOs
  for( int ind = 0 ; ind < 4 ; ind++ ) {
    glBindFramebuffer( GL_FRAMEBUFFER, frameBufferId[ind] );
    
    glGenTextures(1, frameBufferTextureId + ind);
    
    glBindTexture(GL_TEXTURE_2D, frameBufferTextureId[ind]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexStorage2D(GL_TEXTURE_2D,1,GL_RGBA32F,width, height);
    glFramebufferTexture2D( GL_FRAMEBUFFER, 
    			    GL_COLOR_ATTACHMENT0 ,
    			    GL_TEXTURE_2D,
    		 	    frameBufferTextureId[ind] , 
    			    0 );
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER)
       ==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
      printf("Error while Binding RECT FBO color %d texture No %d ID %d (error %d)
" , frameBufferId[ind] , ind , frameBufferTextureId[ind] , glCheckFramebufferStatus(GL_FRAMEBUFFER));
  }
  glDrawBuffers(1, drawBuffers);
  glBindFramebuffer( GL_FRAMEBUFFER, 0 );

  return true;
}



/////////////////////////////////////////////
// texture loading
bool loadtexture( string flieName , int index ) {
  // texture load through OpenCV
  image[index] = cv::imread( flieName, CV_LOAD_IMAGE_COLOR);   // Read the file
  if(! image[index].data ) {                              // Check for invalid input
    printf(  "Could not open or find the image
" );
    return false;
  }
  printf(  "Loaded %s
" , flieName.c_str() );
  glEnable(GL_TEXTURE_2D);
  glGenTextures( 1, &(textureID[index]) );
  glActiveTexture (GL_TEXTURE0 + index);
  glBindTexture( GL_TEXTURE_2D, (textureID[index]) );
  glTexImage2D(GL_TEXTURE_2D,     // Type of texture
	       0,                 // Pyramid level (for mip-mapping) - 0 is the top level
	       GL_RGB,            // Internal colour format to convert to
	       image[index].cols,          // Image width  i.e. 640 for Kinect in standard mode
	       image[index].rows,          // Image height i.e. 480 for Kinect in standard mode
	       0,                 // Border width in pixels (can either be 1 or 0)
	       GL_BGR, // Input image format (i.e. GL_RGB, GL_RGBA, GL_BGR etc.)
	       GL_UNSIGNED_BYTE,  // Image data type
	       image[index].ptr());        // The actual image data itself
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_REPEAT );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  // glGenerateMipmap(GL_TEXTURE_2D);
  return true;
}

/////////////////////////////////////////////
// video frame texture initialization
bool initFrameTexture( IplImage *frame , int index ) {
  glEnable(GL_TEXTURE_2D);
  glGenTextures( 1, &(textureID[index]) );
  glActiveTexture (GL_TEXTURE0 + index);
  glBindTexture( GL_TEXTURE_2D, (textureID[index]) );
  glTexImage2D(GL_TEXTURE_2D,     // Type of texture
	       0,                 // Pyramid level (for mip-mapping) - 0 is the top level
	       GL_R16I,            // Internal colour format to convert to
	       frame->width,          // Image width  i.e. 640 for Kinect in standard mode
	       frame->height,          // Image height i.e. 480 for Kinect in standard mode
	       0,                 // Border width in pixels (can either be 1 or 0)
	       GL_BGR, // Input image format (i.e. GL_RGB, GL_RGBA, GL_BGR etc.)
	       GL_UNSIGNED_BYTE,  // Image data type
	       frame->imageData);        // The actual image data itself
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_REPEAT );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  // glGenerateMipmap(GL_TEXTURE_2D);
  return true;
}

////////////////////////////////////////
// main file
int main () {
  // start GL context and O/S window using the GLFW helper library
  if (!glfwInit ()) {
    fprintf (stderr, "ERROR: could not start GLFW3
");
    return 1;
  } 

  GLFWwindow* window
    //= glfwCreateWindow (2*width, 2*height, "Hello Dice!", NULL, NULL);
    = glfwCreateWindow (width, height, "Hello Dice!", NULL, NULL);
  if (!window) {
    fprintf (stderr, "ERROR: could not open window with GLFW3
");
    glfwTerminate();
    return 1;
  }
  glfwMakeContextCurrent (window);

  // Set key callback function
  glfwSetErrorCallback(error_callback);
  glfwSetKeyCallback(window, key_callback);
  glfwSetCharCallback(window, char_callback);

  // start GLEW extension handler
  glewExperimental = GL_TRUE;
  glewInit ();

  // get version info
  const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
  const GLubyte* version = glGetString (GL_VERSION); // version as a string
  printf ("Renderer: %s
", renderer);
  printf ("OpenGL version supported %s
", version);

  // tell GL to only draw onto a pixel if the shape is closer to the viewer
  glEnable (GL_DEPTH_TEST); // enable depth-testing
  glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"

  // FBO init
  FBOInit();

  // video loading openCV
  //Allocates and initializes cvCapture structure
  // for reading a video stream from the camera.
  //Index of camera is -1 since only one camera
  // connected to the computer or it does not
  // matter what camera to use.
  //CvCapture *input_camera = cvCaptureFromCAM(-1);
  CvCapture *input_camera = cvCaptureFromFile("/home/hibari/gpu_project/videos/toto.avi");
  cvSetCaptureProperty(input_camera, CV_CAP_PROP_FPS, 1);


  //Grabs and returns a frame from camera
  IplImage *frame = NULL; //Preparing frame pointer 
  frame = cvQueryFrame(input_camera);
  // texture loading
  if( !frame ) {
    printf("webcam frame not grabbed!
");
    return -1;
  }
  if( !initFrameTexture( frame , 0 ) ) {
    return -1;
  }

  // texture loading
  if( !loadtexture( "src/jup0vtt2-WB-640x480.png" , 1 ) ) {
    return -1;
  }

  // vertex buffer objects and vertex array
  unsigned int vbo = 0;
  glGenBuffers (1, &vbo);
  glBindBuffer (GL_ARRAY_BUFFER, vbo);
  glBufferData (GL_ARRAY_BUFFER, 
		_NBFACES * 3 * 3 * sizeof (float), 
		points, 
		GL_STATIC_DRAW);
  unsigned int vboTex = 0;
  glGenBuffers (1, &vboTex);
  glBindBuffer (GL_ARRAY_BUFFER, vboTex);
  glBufferData (GL_ARRAY_BUFFER,
		_NBFACES * 3 * 2 * sizeof (float),
		texCoords,
		GL_STATIC_DRAW);

  unsigned int vao = 0;
  glGenVertexArrays (1, &vao);
  glBindVertexArray (vao);
  glBindBuffer (GL_ARRAY_BUFFER, vbo);
  glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
  glEnableVertexAttribArray (0);

  // vertex positions are location 0
  glBindBuffer (GL_ARRAY_BUFFER, vboTex);
  glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
  glEnableVertexAttribArray (1); // don't forget this!


  ////////////////////////////////////////
  // loading and compiling shaders
  unsigned int vs_image = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_image);
  glCompileShader (vs_image);
  printLog(vs_image);

  unsigned int fs_image = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_fs.glsl" , fs_image);
  glCompileShader (fs_image);
  printLog(fs_image);

  unsigned int shader_image_programme = glCreateProgram ();
  glAttachShader (shader_image_programme, fs_image);
  glAttachShader (shader_image_programme, vs_image);
  glLinkProgram (shader_image_programme);

  ////////////////////////////////////////
  // loading and compiling shaders
  unsigned int vs_writeFBO1 = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_writeFBO1);
  glCompileShader (vs_writeFBO1);
  printLog(vs_writeFBO1);

  unsigned int vs_writeFBO2 = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_writeFBO2);
  glCompileShader (vs_writeFBO2);
  printLog(vs_writeFBO2);

  unsigned int vs_writeFBO3 = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_writeFBO3);
  glCompileShader (vs_writeFBO3);
  printLog(vs_writeFBO3);

  unsigned int vs_writeFBO4 = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_writeFBO4);
  glCompileShader (vs_writeFBO4);
  printLog(vs_writeFBO4);

  unsigned int vs_readFBO = glCreateShader (GL_VERTEX_SHADER);
  loadshader( "src/project_vs.glsl" , vs_readFBO);
  glCompileShader (vs_readFBO);
  printLog(vs_readFBO);

  unsigned int fs_writeFBO1 = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_fx1_fs.glsl" , fs_writeFBO1);
  glCompileShader (fs_writeFBO1);
  printLog(fs_writeFBO1);

  unsigned int fs_writeFBO2 = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_fx2_fs.glsl" , fs_writeFBO2);
  glCompileShader (fs_writeFBO2);
  printLog(fs_writeFBO2);

  unsigned int fs_writeFBO3 = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_fx3_fs.glsl" , fs_writeFBO3);
  glCompileShader (fs_writeFBO3);
  printLog(fs_writeFBO3);

  unsigned int fs_writeFBO4 = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_fx4_fs.glsl" , fs_writeFBO4);
  glCompileShader (fs_writeFBO4);
  printLog(fs_writeFBO4);

  unsigned int fs_readFBO = glCreateShader (GL_FRAGMENT_SHADER);
  loadshader( "src/project_readfbo_fs.glsl" , fs_readFBO);
  glCompileShader (fs_readFBO);
  printLog(fs_readFBO);

  unsigned int shader_writeFBO1_programme = glCreateProgram ();
  glAttachShader (shader_writeFBO1_programme, fs_writeFBO1);
  glAttachShader (shader_writeFBO1_programme, vs_writeFBO1);
  glLinkProgram (shader_writeFBO1_programme);

  unsigned int shader_writeFBO2_programme = glCreateProgram ();
  glAttachShader (shader_writeFBO2_programme, fs_writeFBO2);
  glAttachShader (shader_writeFBO2_programme, vs_writeFBO2);
  glLinkProgram (shader_writeFBO2_programme);

  unsigned int shader_writeFBO3_programme = glCreateProgram ();
  glAttachShader (shader_writeFBO3_programme, fs_writeFBO3);
  glAttachShader (shader_writeFBO3_programme, vs_writeFBO3);
  glLinkProgram (shader_writeFBO3_programme);

  unsigned int shader_writeFBO4_programme = glCreateProgram ();
  glAttachShader (shader_writeFBO4_programme, fs_writeFBO4);
  glAttachShader (shader_writeFBO4_programme, vs_writeFBO4);
  glLinkProgram (shader_writeFBO4_programme);

  unsigned int shader_readFBO_programme = glCreateProgram ();
  glAttachShader (shader_readFBO_programme, fs_readFBO);
  glAttachShader (shader_readFBO_programme, vs_readFBO);
  glLinkProgram (shader_readFBO_programme);

  ////////////////////////////////////////
  // shader parameeter bindings
  uniform_image_model = glGetUniformLocation(shader_image_programme, "modelMatrix");
  uniform_image_view = glGetUniformLocation(shader_image_programme, "viewMatrix");
  uniform_image_proj = glGetUniformLocation(shader_image_programme, "projectionMatrix");
  uniform_video_texture = glGetUniformLocation(shader_image_programme, "video");
  uniform_nbFrames = glGetUniformLocation(shader_image_programme, "nbFrames");
  if ( (uniform_image_proj == -1) || (uniform_image_view == -1) 
       || (uniform_image_model == -1) 
       //|| (uniform_mask_texture == -1) 
       || (uniform_video_texture == -1) 
       || (uniform_nbFrames == -1) 
       ) {
    fprintf(stderr, "Could not bind uniforms image
");
    return 0;
  }

  ////////////////////////////////////////
  // shader parameeter bindings
  uniform_readFBO_model = glGetUniformLocation(shader_readFBO_programme, "modelMatrix");
  uniform_readFBO_view = glGetUniformLocation(shader_readFBO_programme, "viewMatrix");
  uniform_readFBO_proj = glGetUniformLocation(shader_readFBO_programme, "projectionMatrix");
  uniform_readFBO_video_texture = glGetUniformLocation(shader_readFBO_programme, "video");
  uniform_texture_FBO1 = glGetUniformLocation(shader_readFBO_programme, "FBO1");
  uniform_texture_FBO2 = glGetUniformLocation(shader_readFBO_programme, "FBO2");
  uniform_texture_FBO3 = glGetUniformLocation(shader_readFBO_programme, "FBO3");
  uniform_texture_FBO4 = glGetUniformLocation(shader_readFBO_programme, "FBO4");
  if ( (uniform_readFBO_proj == -1) || (uniform_readFBO_view == -1) 
       || (uniform_readFBO_model == -1) 
       || (uniform_texture_FBO1 == -1) 
       || (uniform_texture_FBO2 == -1) 
       || (uniform_texture_FBO3 == -1) 
       || (uniform_texture_FBO4 == -1) 
       ) {
    fprintf(stderr, "Could not bind uniforms readFBO
");
    // return 0;
  }

  ////////////////////////////////////////
  // endless rendering loop
  int nbFrames = 0;
  while (!glfwWindowShouldClose (window)) {

    // projection matrix
    glm::mat4 projectionMatrix; // Store the projection matrix
    glm::mat4 viewMatrix; // Store the view matrix
    glm::mat4 modelMatrix; // Store the model matrix

    // Projection: Ortho matrix
    projectionMatrix
      = glm::ortho(0.0f,(float)width,(float)height,0.0f);
    
    // Camera matrix
    viewMatrix =  glm::mat4(1.0f);

    // Model matrix : an identity matrix (model will be at the origin)
    modelMatrix = glm::mat4(1.0f); 


    //////////////////////////////////////////////////
    // PASS #1
    // output buffer cleanup
	 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
	 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId[0]);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    ////////////////////////////////////////
    // activate shaders and sets uniform variable values    
    glUseProgram(shader_image_programme);
    glBindVertexArray (vao);
    glUniformMatrix4fv(uniform_image_proj, 1, GL_FALSE, 
		       glm::value_ptr(projectionMatrix));
    glUniformMatrix4fv(uniform_image_view, 1, GL_FALSE, 
		       glm::value_ptr(viewMatrix));
    glUniformMatrix4fv(uniform_image_model, 1, GL_FALSE, 
		       glm::value_ptr(modelMatrix));
    
    glUniform1i(uniform_video_texture, 0); //Texture unit 1

    glUniform1i(uniform_nbFrames, nbFrames); 

    // input texture (loaded texture)
    glActiveTexture(GL_TEXTURE0 + 0);
    glBindTexture(GL_TEXTURE_2D, textureID[0]);

    // frame capture
    frame = cvQueryFrame(input_camera);
    glTexImage2D(GL_TEXTURE_2D,     // Type of texture
		 0,                 // Pyramid level (for mip-mapping) - 0 is the top level
		 GL_RGB,            // Internal colour format to convert to
		 frame->width,          // Image width  i.e. 640 for Kinect in standard mode
		 frame->height,          // Image height i.e. 480 for Kinect in standard mode
		 0,                 // Border width in pixels (can either be 1 or 0)
		 GL_BGR, // Input image format (i.e. GL_RGB, GL_RGBA, GL_BGR etc.)
		 GL_UNSIGNED_BYTE,  // Image data type
		 frame->imageData);        // The actual image data itself
    
    // draw points from the currently bound VAO with current in-use shader
    glDrawArrays (GL_TRIANGLES, 0, _NBFACES * 3);

	 //glBindFramebuffer(GL_FRAMEBUFFER, 0);
	 glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId[0]);
	 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    ////////////////////////////////////////
    // activate shaders and sets uniform variable values    
    glUseProgram (shader_readFBO_programme);
    glBindVertexArray (vao);
    glUniformMatrix4fv(uniform_readFBO_proj, 1, GL_FALSE, 
		       glm::value_ptr(projectionMatrix));
    glUniformMatrix4fv(uniform_readFBO_view, 1, GL_FALSE, 
		       glm::value_ptr(viewMatrix));
    glUniformMatrix4fv(uniform_readFBO_model, 1, GL_FALSE, 
		       glm::value_ptr(modelMatrix));

    glUniform1i(uniform_readFBO_video_texture, 0); //Texture unit 1

    // input texture (loaded texture)
    glActiveTexture(GL_TEXTURE0 + 0);
    glBindTexture(GL_TEXTURE_2D, frameBufferId[0]);

    // draw points from the currently bound VAO with current in-use shader
    glDrawArrays (GL_TRIANGLES, 0, _NBFACES * 3);
     
     ///////////////////////////////////////
    // EVENTS + FB swap

    // update other events like input handling 
    glfwPollEvents ();

    // put the stuff we've been drawing onto the display
    glfwSwapBuffers (window);

    nbFrames++;
  }


  //Release cvCapture structure
  cvReleaseCapture(&input_camera);

  // close GL context and any other GLFW resources
  glfwDestroyWindow(window);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}


Here is a pastebin because the line numbers are not displayed with the “code” tags :
pastebin.com/GLxwYjpT

My problem is on the lines 433-434 and 472-473.
For the first pass i’m using :


glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId[0]);

and for the second pass :


glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

Despite of that, i have a black screen.
Can someone tell what i did wrong ? It would be nice.

Thanks everybody.

The read framebuffer is for operations that read from the framebuffer itself. Fragment shaders cannot read from a framebuffer; they can read from textures.

So you need to bind the texture that was previously written to.

A thousand of thanks Mr. Reinheart. I spent the all day on it without seeing this mistake (beginners).

To sum up, i had to replace


glBindTexture(GL_TEXTURE_2D, frameBufferId[0];

by


glBindTexture(GL_TEXTURE_2D, frameBufferTextureId[0];

Thanks again !

How can i mark my thread as solved ?