GLSL Render To FBO using MRT

Hello,

I would like to implement a very simple program before starting the more advanced one, since I am new in writing shaders. My aim is to write simple constant values to first target using my first program and 2 shaders, then read and use them in the second program using a different shader. I am simply working on the lighthouse flatten shader using 2 teapots. By the way I am taking a little help from a code that I found in internet but it is not working either. My result is always black. If I can not manage this simple one, I can not manage the advanced one. I appreciate if you can check my code. Many thanks in advance. Here is my code:

GLint loc;
GLuint v,f,f2,p,p2;
int s;

int texSize = 320;
GLuint outputTextures[2];
GLuint inputTextures;
GLenum myBuffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
GLuint fb;
float* input;

void setupTexture (GLuint id)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB,id);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(v, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_FLOAT_R32_NV,texSize,texSize,0,GL_LUMINANCE,GL_FLOAT,0);
}

void changeSize(int w, int h)
{

// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
	h = 1;

float ratio = 1.0* w / h;

// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Set the viewport to be the entire window
    glViewport(0, 0, w, h);

// Set the correct perspective.
gluPerspective(45,ratio,1,100);
glMatrixMode(GL_MODELVIEW);

}

float t = 0;

void renderScene(void)
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
gluLookAt(0.0,5.0,5.0, 
	      0.0,0.0,0.0,
		  0.0f,1.0f,0.0f);

glUniform1f(loc, t);

float color1[4] = {1,0,0,1};
float color2[4] = {1,1,0,1};

glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color1);
glutSolidTeapot(1);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color2);
glTranslatef(0,1,0);
glutSolidTeapot(1);
t+=0.01;

glutSwapBuffers();

}

void processNormalKeys(unsigned char key, int x, int y)
{

if (key == 27) 
	exit(0);

}

void setShaders()
{

char *vs = NULL,*fs = NULL,*fs2 = NULL;

v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
f2 = glCreateShader(GL_FRAGMENT_SHADER);


vs = textFileRead("flatten.vert");
fs = textFileRead("flattenBegin.frag");
fs2 = textFileRead("flatten1.frag");

const char * vv = vs;
const char * ff = fs;
const char * ff2 = fs2;

glShaderSource(v, 1, &vv,NULL);
glShaderSource(f, 1, &ff,NULL);
glShaderSource(f2, 1, &ff2,NULL);

free(vs);
free(fs);
free(fs2);

if(s==1)
{
	glCompileShader(v);
	glCompileShader(f);
	printShaderInfoLog(v);
	printShaderInfoLog(f);
	p = glCreateProgram();
	glAttachShader(p,v);
	glAttachShader(p,f);
	glLinkProgram(p);
	printProgramInfoLog(p);
	loc = glGetUniformLocation(p,"time");
}
else if (s==2)
{
	glCompileShader(v);
	glCompileShader(f2);
	printShaderInfoLog(v);
	printShaderInfoLog(f2);
	p2 = glCreateProgram();
	glAttachShader(p2,v);
	glAttachShader(p2,f2);
	glLinkProgram(p2);
	printProgramInfoLog(p2);
	loc = glGetUniformLocation(p2,"time");
}

}

int main(int argc, char *argv)
{
input = (float
)malloc(texSizetexSizesizeof(float));

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(320,320);
glutCreateWindow("SimpleMRT");

glewInit();

glGenFramebuffersEXT(1, &fb); 
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

glutReshapeFunc(changeSize);
glutKeyboardFunc(processNormalKeys);


glGenTextures (1, &inputTextures);
setupTexture (inputTextures);

glGenTextures (2, outputTextures);
for (int i=0; i<2; i++)
	setupTexture (outputTextures[i]);


s = 1;
setShaders();

//Bind output textures
for (int i=0; i<2; i++) 
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, myBuffers[i], GL_TEXTURE_RECTANGLE_ARB, outputTextures[i], 0);

checkFramebufferStatus();
glUseProgram(p);
//set render destination
glDrawBuffers(2,myBuffers);
glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0);
	glVertex2f(0.0, 0.0);

	glTexCoord2f(texSize, 0.0);
	glVertex2f(texSize, 0.0);

	glTexCoord2f(texSize, texSize);
	glVertex2f(texSize, texSize);

	glTexCoord2f(0.0, texSize);
	glVertex2f(0.0, texSize);
glEnd();
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);


//Read from myBuffers
glReadBuffer(myBuffers[1]);
glReadPixels(0, 0, texSize, texSize, GL_LUMINANCE, GL_FLOAT, input);

//Transfer those read values to the input texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, outputTextures[1]);

glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,texSize,texSize,GL_LUMINANCE,GL_FLOAT,input);

s = 2;
setShaders();
glUseProgram(p2);
glUniform1i(glGetUniformLocation(p2, "input"),0);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);

glDeleteFramebuffersEXT(1,&fb);
glDeleteTextures(1,&inputTextures);
glDeleteTextures(2,outputTextures);

glEnable(GL_DEPTH_TEST);
glClearColor(1.0,1.0,1.0,1.0);

glutMainLoop();
return 0;

}

VERTEX SHADER:
uniform float time;

void main(void)
{
vec4 v = vec4(gl_Vertex);

v.z = sin(5.0*v.x+time)*0.5;

gl_Position = gl_ModelViewProjectionMatrix * v;

}

FRAGMENT SHADER 1:
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable

void main()
{
gl_FragData[1].x = 0.3;
}

FRAGMENT SHADER 2:
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect input;

void main(void)
{
vec2 coords = gl_TexCoord[0].xy;
float color = texture2DRect(input, coords).x;
gl_FragColor = color * gl_FrontMaterial.ambient;
}

I don’t think that you can have two fragment shaders attached to one glsl program. Instead I would recommend reading the article that explains rendering to multiple targets and then displaying the resulting texture. For some reason there is no link to the original sample code – I have attached my modified version of it for you to look at if helpful – it uses gl3.h header but on windows you will probably have to modify it to use glew instead

also why are you deleting before starting the rendering loop?


	glDeleteFramebuffersEXT(1,&fb);
	glDeleteTextures(1,&inputTextures);
	glDeleteTextures(2,outputTextures);

This means that you don’t have them when you actually start rendering. Nothing gets rendered until only after glutMainLoop is called!

Also your renderScene call is simply drawing two x offset teapots – is that what you are intending? This is not doing any multiple render target stuff if that is the case.

Correction – I looked too quickly at your code – Ignore my incorrect statement “I don’t think that you can have two fragment shaders attached to one glsl program.” That is not your case.

Heres a modified version of your original post that demonstrates MRT. It renders a wobbling set of teapots to two FBO textures; first red second green. Then uses those textures on two quads each with one of the textures. Notice that no need to use readPixels nor the malloc’ed CPU-side “*input” array.

A second key point is the addition of the line


gl_TexCoord[0] = gl_MultiTexCoord0;

to your VERTEX shader.

flattenBegin.frag


#version 120
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable

void main()
{
gl_FragData[0] = vec4(1.0,0.0,0.0,1.0);
gl_FragData[1] = vec4(0.0,1.0,0.0,1.0);
}

flatten1.frag


#version 120
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect input;

void main(void)
{
//vec2 coords = gl_TexCoord[0].st; // not .xy
//float color = texture2DRect(input, coords).x;
//gl_FragColor = color * gl_FrontMaterial.ambient;
//
//gl_FragColor = vec4(0.0,0.0,1.0,1.0);
//gl_FragColor = vec4(gl_TexCoord[0].s/512.0,gl_TexCoord[0].t/512.0,0.0,1.0);
//gl_FragColor = texture2DRect(input, vec2(266.0,209.0));
gl_FragColor = texture2DRect(input, gl_TexCoord[0].st);
}

flatten.vert


uniform float time;

void main(void)
{
vec4 v = vec4(gl_Vertex);

v.z = sin(5.0*v.x+time)*0.5;

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * v;
}

main.c


#include <GL/glew.h>
#include <GL/glut.h>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstring>

//GLint loc_1;
//GLint loc_2;
GLuint v,f,f2,p,p2;

int texSize = 512;
GLuint outputTextures[2];
//GLuint inputTextures;
GLuint fb;
GLuint depthBuffer;      // Our handle to the depth render buffer

//float* input;

void printShaderInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 1)
  {
    infoLog = (char *)malloc(infologLength);
    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}

void printProgramInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 1)
  {
    infoLog = (char *)malloc(infologLength);
    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}

const char *textFileRead(const char *fn) 
{
  FILE *fp;
  char *content = NULL;

  int count=0;

  if (fn != NULL) 
  {
    fp = fopen(fn,"rt");

    if (fp != NULL) 
    {
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

      if (count > 0) 
      {
        content = (char *)malloc(sizeof(char) * (count+1));
        count = fread(content,sizeof(char),count,fp);
        content[count] = '\0';
      }
      fclose(fp);
    }
  }
  return content;
}

void setupTexture (GLuint id)
{
  glBindTexture(GL_TEXTURE_RECTANGLE,id);
  //glTexImage2D(GL_TEXTURE_RECTANGLE,0,GL_FLOAT_R32_NV,texSize,texSize,0,GL_LUMINANCE,GL_FLOAT,0);
  glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA8,  texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}


void changeSize(int w, int h)
{
  // Prevent a divide by zero, when window is too short
  // (you cant make a window of zero width).
  if(h == 0)
    h = 1;

  float ratio = 1.0* w / h;

  // Set the viewport to be the entire window
  glViewport(0, 0, w, h);

  // Reset the coordinate system before modifying
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  // Set the correct perspective.
  gluPerspective(45,ratio,1,100);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}


float t = 0;

void renderScene(void)
{
  t+=0.01;

  // First we bind the FBO so we can render to it
  glBindFramebuffer(GL_FRAMEBUFFER, fb);
  glClearColor(0.3,0.3,0.3,1.0);
  glPushAttrib(GL_VIEWPORT_BIT);
  glViewport(0,0,texSize,texSize);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glUseProgram(p);
  glUniform1f(glGetUniformLocation(p,"time"), t);

  glLoadIdentity();
  gluLookAt(0.0,5.0,5.0,
    0.0,0.0,0.0,
    0.0f,1.0f,0.0f);

  //float color1[4] = {1,0,0,1};
  //float color2[4] = {1,1,0,1};

  //Transfer those read values to the input texture
  //glActiveTexture(GL_TEXTURE0);
  //glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[0]);
  //glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color1);
  glutSolidTeapot(1);

  //Transfer those read values to the input texture
  //glActiveTexture(GL_TEXTURE1);
  //glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color2);
  //glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[1]);
  glTranslatef(0,2,0);
  glutSolidTeapot(1);

  glPopAttrib();

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  glClearColor(0.6,0.6,0.6,1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


  glUseProgram(p2);
  glUniform1f(glGetUniformLocation(p2,"time"), t);

  glLoadIdentity();
  gluLookAt(0.0,5.0,5.0,
    0.0,0.0,0.0,
    0.0f,1.0f,0.0f);

  //Transfer those read values to the input texture
  glUniform1i(glGetUniformLocation(p2, "input"),0);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[1]);

  glBegin(GL_QUADS);
  glTexCoord2i(      0,       0); glVertex2f(-0.0, 0.0);
  glTexCoord2i(texSize,       0); glVertex2f(-1.0, 0.0);
  glTexCoord2i(texSize, texSize); glVertex2f(-1.0, 1.0);
  glTexCoord2i(      0, texSize); glVertex2f(-0.0, 1.0);
  glEnd();

  glUniform1i(glGetUniformLocation(p2, "input"),1);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[0]);

  glBegin(GL_QUADS);
  glTexCoord2i(      0,       0); glVertex2f(0.0, 0.0);
  glTexCoord2i(texSize,       0); glVertex2f(1.0, 0.0);
  glTexCoord2i(texSize, texSize); glVertex2f(1.0, 1.0);
  glTexCoord2i(      0, texSize); glVertex2f(0.0, 1.0);
  glEnd();

  glUseProgram(0);

  glutSwapBuffers();
  glutPostRedisplay();
}

void processNormalKeys(unsigned char key, int x, int y)
{

  if (key == 27)
    exit(0);
}

void setShaders(int s)
{
  const char *vs = textFileRead("flatten.vert");
  const char *fs = textFileRead("flattenBegin.frag");
  const char *fs2 = textFileRead("flatten1.frag");

  v = glCreateShader(GL_VERTEX_SHADER);
  f = glCreateShader(GL_FRAGMENT_SHADER);
  f2 = glCreateShader(GL_FRAGMENT_SHADER);

  glShaderSource(v,  1, &vs,NULL);
  glShaderSource(f,  1, &fs,NULL);
  glShaderSource(f2, 1,&fs2,NULL);

  free((void*)vs);
  free((void*)fs);
  free((void*)fs2);

  if(s==1)
  {
    glCompileShader(v);
    glCompileShader(f);
    printShaderInfoLog(v);
    printShaderInfoLog(f);
    p = glCreateProgram();
    glAttachShader(p,v);
    glAttachShader(p,f);
    glLinkProgram(p);
    printProgramInfoLog(p);
    //loc_1 = glGetUniformLocation(p,"time");
  }
  else if (s==2)
  {
    glCompileShader(v);
    glCompileShader(f2);
    printShaderInfoLog(v);
    printShaderInfoLog(f2);
    p2 = glCreateProgram();
    glAttachShader(p2,v);
    glAttachShader(p2,f2);
    glLinkProgram(p2);
    printProgramInfoLog(p2);
    //loc_2 = glGetUniformLocation(p2,"time");
  }
}

void cleanup(void)
{
  glDeleteFramebuffers(1,&fb);
  //glDeleteTextures(1,&inputTextures);
  glDeleteTextures(2,outputTextures);
  //if (input) free(input);
}


void initGL(void)
{
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_DEPTH_TEST);
  glClearColor(1.0,1.0,1.0,1.0);

  glGenFramebuffers(1, &fb);
  glBindFramebuffer(GL_FRAMEBUFFER, fb);

  // Create the render buffer for depth  
  glGenRenderbuffers(1, &depthBuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, texSize, texSize);

//  glGenTextures (1, &inputTextures);
//  setupTexture (inputTextures);

  glGenTextures (2, outputTextures);
  for (int i=0; i<2; i++)
    setupTexture (outputTextures[i]);

  //Bind output textures
  for (int i=0; i<2; i++)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_RECTANGLE, outputTextures[i], 0);

  // Attach the depth render buffer to the FBO as it's depth attachment
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);

  // Define an array which contains the targets we wish to render to...
  GLenum myBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
  // ... then inform OpenGL that we wish to render to these two targets
  glDrawBuffers(2,myBuffers);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if(status != GL_FRAMEBUFFER_COMPLETE)
    exit(1);

  glBindFramebuffer(GL_FRAMEBUFFER, 0);  // Unbind the FBO for now

  setShaders(1);
  setShaders(2);

  //Storage to Read into from myBuffers
  //input = (float*)malloc(texSize*texSize*sizeof(float));
}

int main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
  glutInitWindowPosition(100,100);
  glutInitWindowSize(texSize,texSize);
  glutCreateWindow("SimpleMRT");
  glutReshapeFunc(changeSize);
  glutKeyboardFunc(processNormalKeys);
  glutDisplayFunc(renderScene);

  glewInit();

  initGL();
  atexit(cleanup);

  glutMainLoop();
  return 0;
}

Hello marshats, thank you for your quick response. There is a point I want to make clear. I am trying to run a very simple multi-pass program. So in the 1st pass, I write some constant values to a target and in the 2nd pass, I try to read them and make some random operations, e.g. multiplying this value with the original color of the teapots. However in your corrected version, I saw that you are calling the programs(actually shaders) one after another without rendering the scene in between. Since I do not have any experience with multi-pass rendering, I am wondering if my thought is wrong or not.

I saw that you are calling the programs(actually shaders) one after another without rendering the scene in between

Actually I am “rendering” in between. I couldn’t figure out what you were originally trying to do so I just tried to show how to use a FBO for writing into multiple textures then how to read back from those textures.

The first shader program uses the FBO and writes fragments into it’s two attached textures; one green and the other red. In the second shader program I read from those FBO generated textures to “paint onto” two separate 4-point Quads, but this time rendering to the screen. Think of the first render scene going to the textures rather than the screen and the second render going to what you see on the screen.

So it has all the features of what you desire – how to write into separate textures two solid colors wherever the teapots are drawn with the FBO and then how to read back from the FBO generated textures in the second shader program.

here’s some more code along the lines that you wanted. The top two rectangles drawn with render02 are extraneous but just to show you what the textures are after rendering to fbo (render01) the bottom rectangle results from render03 and is the multiplication of the two textures.

flatten.vert


uniform float time;

void main(void)
{
vec4 v = vec4(gl_Vertex);

v.z = sin(5.0*v.x+time)*0.5;

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * v;
}

flattenBegin.frag


#version 120
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable

void main()
{
  gl_FragData[0] = vec4(0.0,0.0,0.8,0.0);
  gl_FragData[1] = gl_FrontMaterial.ambient;
}

flatten1.frag


#version 120
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect input;

void main(void)
{
  gl_FragColor = texture2DRect(input, gl_TexCoord[0].st);
}

flatten3.frag


#version 120
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect input0;
uniform sampler2DRect input1;

void main(void)
{
  vec4 color0 = texture2DRect(input0, gl_TexCoord[0].st);
  vec4 color1 = texture2DRect(input1, gl_TexCoord[0].st);
  if (color0.a==0.0) 
   gl_FragColor = color0.z*color1; //color * gl_FrontMaterial.ambient;
  else
   gl_FragColor = color1;
}

main.c


#include <GL/glew.h>
#include <GL/glut.h>

#include <cstdio>
#include <cstdlib>
#include <cstring>

//GLint loc_1;
//GLint loc_2;
GLuint v,f,f2,f3,p,p2,p3;

const int texSize = 612;
GLuint outputTextures[2];
//GLuint inputTextures;
GLuint fb;
GLuint depthBuffer;         // Our handle to the depth render buffer

//float* input;

float t = 0;           // time

void printShaderInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 1)
  {
    infoLog = (char *)malloc(infologLength);
    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}


void printProgramInfoLog(GLuint obj)
{
  int infologLength = 0;
  int charsWritten  = 0;
  char *infoLog;

  glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

  if (infologLength > 1)
  {
    infoLog = (char *)malloc(infologLength);
    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
    printf("%s
",infoLog);
    free(infoLog);
  }
}


const char *textFileRead(const char *fn)
{
  FILE *fp;
  char *content = NULL;

  int count=0;

  if (fn != NULL)
  {
    fp = fopen(fn,"rt");

    if (fp != NULL)
    {
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

      if (count > 0)
      {
        content = (char *)malloc(sizeof(char) * (count+1));
        count = fread(content,sizeof(char),count,fp);
        content[count] = '\0';
      }
      fclose(fp);
    }
  }
  return content;
}


void setupTexture (GLuint id)
{
  glBindTexture(GL_TEXTURE_RECTANGLE,id);
  //glTexImage2D(GL_TEXTURE_RECTANGLE,0,GL_FLOAT_R32_NV,texSize,texSize,0,GL_LUMINANCE,GL_FLOAT,0);
  glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA8,  texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}


void changeSize(int w, int h)
{
  // Prevent a divide by zero, when window is too short
  // (you cant make a window of zero width).
  if(h == 0)
    h = 1;

  // Set the viewport to be the entire window
  glViewport(0, 0, w, h);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  float ratio = 1.0* w / h;
  gluPerspective(45,ratio,1,100);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}


void RenderPass01(float t)
{
  glUseProgram(p);
  glUniform1f(glGetUniformLocation(p,"time"), t);

  glLoadIdentity();
  gluLookAt(0.0,5.0,5.0,
    0.0,0.0,0.0,
    0.0,1.0,0.0);

  float color1[4] = {1,0,0,1};
  float color2[4] = {1,1,0,1};

  //Transfer those read values to the input texture
  //glActiveTexture(GL_TEXTURE0);
  //glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[0]);
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color1);
  glutSolidTeapot(1);

  //Transfer those read values to the input texture
  //glActiveTexture(GL_TEXTURE1);
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color2);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[1]);
  glTranslatef(0,2,0);
  glutSolidTeapot(1);
}


void RenderPass02(float t)
{
  glUseProgram(p2);
  glUniform1f(glGetUniformLocation(p2,"time"), t);

  glLoadIdentity();
  gluLookAt(0.0,5.0,5.0,
    0.0,0.0,0.0,
    0.0,1.0,0.0);

  //set input texture to use outputTextures[1]
  glUniform1i(glGetUniformLocation(p2, "input"),0);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[0]);

  glBegin(GL_QUADS);
  glTexCoord2i(      0,       0); glVertex2f(-0.0, 0.0);
  glTexCoord2i(texSize,       0); glVertex2f(-1.0, 0.0);
  glTexCoord2i(texSize, texSize); glVertex2f(-1.0, 1.0);
  glTexCoord2i(      0, texSize); glVertex2f(-0.0, 1.0);
  glEnd();

  //set input texture to use outputTextures[0]
  glUniform1i(glGetUniformLocation(p2, "input"),1);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[1]);

  glBegin(GL_QUADS);
  glTexCoord2i(      0,       0); glVertex2f(0.0, 0.0);
  glTexCoord2i(texSize,       0); glVertex2f(1.0, 0.0);
  glTexCoord2i(texSize, texSize); glVertex2f(1.0, 1.0);
  glTexCoord2i(      0, texSize); glVertex2f(0.0, 1.0);
  glEnd();
}

void RenderPass03(float t)
{
  glUseProgram(p3);
  glUniform1f(glGetUniformLocation(p3,"time"), t);

  glLoadIdentity();
  gluLookAt(0.0,5.0,5.0,
    0.0,0.0,0.0,
    0.0,1.0,0.0);

  //set input texture to use outputTextures[1]
  glUniform1i(glGetUniformLocation(p3, "input0"),0);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[0]);

  //set input texture to use outputTextures[0]
  glUniform1i(glGetUniformLocation(p3, "input1"),1);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_RECTANGLE, outputTextures[1]);

  glTranslatef(-0.5,-1.0,0.0);
  glBegin(GL_QUADS);
  glTexCoord2i(      0,       0); glVertex2f(-0.0, 0.0);
  glTexCoord2i(texSize,       0); glVertex2f(-1.0, 0.0);
  glTexCoord2i(texSize, texSize); glVertex2f(-1.0, 1.0);
  glTexCoord2i(      0, texSize); glVertex2f(-0.0, 1.0);
  glEnd();
}


void renderScene(void)
{
  t+=0.01;

  // First we bind the FBO so we can render to it
  glBindFramebuffer(GL_FRAMEBUFFER, fb);
  glClearColor(1.0,0.65,0.0,1.0); //orange background
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushAttrib(GL_VIEWPORT_BIT);
  glViewport(0,0,texSize,texSize);
  RenderPass01(t);
  glPopAttrib();

  // Second we bind to the default FBO (display screen) and render to it
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  glClearColor(0.6,0.6,0.6,1.0); // grey background
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  RenderPass02(t); // just to show the two textures from FBO

  // Third
  RenderPass03(t); // actually combine the colors

  // Finally, good practice to end with default shader program
  glUseProgram(0);

  glutSwapBuffers();
  glutPostRedisplay();
}


void processNormalKeys(unsigned char key, int x, int y)
{
  if (key == 27)
    exit(0);
}


void setShaders(void)
{
  const char *vs = textFileRead("flatten.vert");
  const char *fs = textFileRead("flattenBegin.frag");
  const char *fs2 = textFileRead("flatten1.frag");
  const char *fs3 = textFileRead("flatten3.frag");

  v = glCreateShader(GL_VERTEX_SHADER);
  f = glCreateShader(GL_FRAGMENT_SHADER);
  f2 = glCreateShader(GL_FRAGMENT_SHADER);
  f3 = glCreateShader(GL_FRAGMENT_SHADER);

  glShaderSource(v,  1, &vs,NULL);
  glShaderSource(f,  1, &fs,NULL);
  glShaderSource(f2, 1,&fs2,NULL);
  glShaderSource(f3, 1,&fs3,NULL);

  free((void*)vs);
  free((void*)fs);
  free((void*)fs2);

  //if(s==1)
  {
    glCompileShader(v);
    glCompileShader(f);
    printShaderInfoLog(v);
    printShaderInfoLog(f);
    p = glCreateProgram();
    glAttachShader(p,v);
    glAttachShader(p,f);
    glLinkProgram(p);
    printProgramInfoLog(p);
    //loc_1 = glGetUniformLocation(p,"time");
  }
  //else if (s==2)
  {
    glCompileShader(v);
    glCompileShader(f2);
    printShaderInfoLog(v);
    printShaderInfoLog(f2);
    p2 = glCreateProgram();
    glAttachShader(p2,v);
    glAttachShader(p2,f2);
    glLinkProgram(p2);
    printProgramInfoLog(p2);
    //loc_2 = glGetUniformLocation(p2,"time");
  }
  {
    p3 = glCreateProgram();
    glAttachShader(p3,v);
    glAttachShader(p3,f3);
    glLinkProgram(p3);
    printProgramInfoLog(p3);
  }
}


void cleanup(void)
{
  //if (input) free(input);
  glDeleteTextures(2,outputTextures);
  //glDeleteTextures(1,&inputTextures);
  glDeleteRenderbuffers(1, &depthBuffer);
  glDeleteFramebuffers(1,&fb);
  glDeleteProgram(p3);
  glDeleteProgram(p2);
  glDeleteProgram(p);
  glDeleteShader(f3);
  glDeleteShader(f2);
  glDeleteShader(f);
  glDeleteShader(v);
}


void defineFrameBuffer(void)
{
  glGenFramebuffers(1, &fb);
  glBindFramebuffer(GL_FRAMEBUFFER, fb);

  // Create the render buffer for depth
  glGenRenderbuffers(1, &depthBuffer);
  glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, texSize, texSize);

  // Attach the depth render buffer to the FBO as it's depth attachment
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);

  //  glGenTextures (1, &inputTextures);
  //  setupTexture (inputTextures);

  glGenTextures (2, outputTextures);
  for (int i=0; i<2; i++)
    setupTexture (outputTextures[i]);

  //Bind output textures
  for (int i=0; i<2; i++)
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, outputTextures[i], 0);

  // Define an array which contains the targets we wish to render to...
  GLenum myFragmentColorBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
  // ... then inform OpenGL that we wish to render to these two targets
  glDrawBuffers(2,myFragmentColorBuffers);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if(status != GL_FRAMEBUFFER_COMPLETE)
    exit(1);

                 // Unbind the FBO for now
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}


void initGL(void)
{
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_DEPTH_TEST);

  defineFrameBuffer();
  setShaders();

  //Storage to Read into from myBuffers
  //input = (float*)malloc(texSize*texSize*sizeof(float));
}


int main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
  glutInitWindowPosition(100,100);
  glutInitWindowSize(texSize,texSize);
  glutCreateWindow("SimpleMRT");
  glutReshapeFunc(changeSize);
  glutKeyboardFunc(processNormalKeys);
  glutDisplayFunc(renderScene);

  glewInit();

  initGL();
  atexit(cleanup);

  glutMainLoop();
  return 0;
}

marshats, thank you very much. I think I got the idea now:)

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.