PDA

View Full Version : GLSL Render To FBO using MRT



gmak26
01-28-2011, 06:45 AM
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_R 32_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(texSize*texSize*sizeof(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,tex Size,texSize,GL_LUMINANCE,GL_FLOAT,input);

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

glDeleteFramebuffersEXT(1,&amp;fb);
glDeleteTextures(1,&amp;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;
}

marshats
01-29-2011, 09:07 AM
I don't think that you can have two fragment shaders attached to one glsl program. Instead I would recommend reading the article (http://www.gamedev.net/page/resources/_/reference/programming/opengl/opengl-frame-buffer-object-201-r2333) 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,&amp;fb);
glDeleteTextures(1,&amp;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.

marshats
01-29-2011, 04:16 PM
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.

marshats
01-29-2011, 11:24 PM
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,&amp;infologLength);

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

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

glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&amp;infologLength);

if (infologLength > 1)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &amp;charsWritten, infoLog);
printf("%s\n",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_N V,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, &amp;vs,NULL);
glShaderSource(f, 1, &amp;fs,NULL);
glShaderSource(f2, 1,&amp;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,&amp;fb);
//glDeleteTextures(1,&amp;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, &amp;fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);

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

// glGenTextures (1, &amp;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(&amp;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;
}

gmak26
01-31-2011, 03:45 AM
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.

marshats
01-31-2011, 06:15 PM
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,&amp;infologLength);

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


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

glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&amp;infologLength);

if (infologLength > 1)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &amp;charsWritten, infoLog);
printf("%s\n",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_N V,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, &amp;vs,NULL);
glShaderSource(f, 1, &amp;fs,NULL);
glShaderSource(f2, 1,&amp;fs2,NULL);
glShaderSource(f3, 1,&amp;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,&amp;inputTextures);
glDeleteRenderbuffers(1, &amp;depthBuffer);
glDeleteFramebuffers(1,&amp;fb);
glDeleteProgram(p3);
glDeleteProgram(p2);
glDeleteProgram(p);
glDeleteShader(f3);
glDeleteShader(f2);
glDeleteShader(f);
glDeleteShader(v);
}


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

// Create the render buffer for depth
glGenRenderbuffers(1, &amp;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, &amp;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(&amp;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;
}

gmak26
02-01-2011, 05:41 AM
marshats, thank you very much. I think I got the idea now:)