Seriously don't understand WHY my framebuffer isn't rendering as a texture

Started by
23 comments, last by Ignifex 11 years, 9 months ago

hi,

here's a tiny little program that does fbos, hope this will help you. (The result you should see is a white triangle)


#include <iostream>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#undef near
#undef far
#endif

#include "GL/glew.h" //the mighty GLEW :)
#include "SFML/Window.hpp"

/*
* Global variables
*/

sf::Window the_window;
sf::Event the_event;

float fps = 1.0f;
int frames = 0;
sf::Clock the_clock;
std::string app_path;
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

GLuint tex;

GLuint fbo;

/*
* Function declarations
*/

void get_opengl_error( bool ignore = false );

void draw_quad()
{
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 );
glVertex2f( 0, 0 );
glTexCoord2f( 1, 0 );
glVertex2f( 1, 0 );
glTexCoord2f( 1, 1 );
glVertex2f( 1, 1 );
glTexCoord2f( 0, 1 );
glVertex2f( 0, 1 );
glEnd();
}

void check_fbo()
{
if( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE )
{
std::cerr << "FBO not complete.\n";
the_window.close();
exit( 1 );
}
}


int main( int argc, char* args[] )
{
/*
* Initialize OpenGL context
*/

the_window.create( sf::VideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 32 ), "FBO", sf::Style::Default );

if( !the_window.isOpen() )
{
std::cerr << "Couldn't initialize SFML.\n";
the_window.close();
exit( 1 );
}

GLenum glew_error = glewInit();

if( glew_error != GLEW_OK )
{
std::cerr << "Error initializing GLEW: " << glewGetErrorString( glew_error ) << "\n";
the_window.close();
exit( 1 );
}

if( !GLEW_VERSION_3_3 )
{
std::cerr << "Error: OpenGL 3.3 is required\n";
the_window.close();
exit( 1 );
}

/*
* Initialize and load textures
*/

glEnable( GL_TEXTURE_2D );

glGenTextures( 1, &tex );
glBindTexture( GL_TEXTURE_2D, tex );
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_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0 );

get_opengl_error();

/*
* Initialize FBOs
*/

GLenum modes[] = { GL_COLOR_ATTACHMENT0 };

glGenFramebuffers( 1, &fbo );
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
glDrawBuffers( 1, modes );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0 );

check_fbo();

glBindFramebuffer( GL_FRAMEBUFFER, 0 );

glBindTexture( GL_TEXTURE_2D, 0 );

get_opengl_error();


/*
* Set up matrices
*/

glViewport( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
glMatrixMode( GL_PROJECTION );
//x_min:0, x_max:1, y_min:0, y_max:1, z_min:0, z_max:-1
float ortho_matrix[] = { 2, 0, 0, 0,
0, 2, 0, 0,
0, 0, 2, 0,
-1, -1, -1, 1
};
glLoadMatrixf( ortho_matrix );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

get_opengl_error();

/*
* Generate input
*/

glBindFramebuffer( GL_FRAMEBUFFER, fbo );

glClearColor( 0, 0, 0, 0 );
glClear( GL_COLOR_BUFFER_BIT );

glPushMatrix();
glTranslatef( 0.5f, 0.5f, 0.0f );
glBegin( GL_TRIANGLES );
glColor3f( 1, 1, 1 );
glVertex2f( -0.25f, -0.25f );
glVertex2f( 0, 0.25f );
glVertex2f( 0.25f, -0.25f );
glEnd();
glPopMatrix();

glBindFramebuffer( GL_FRAMEBUFFER, 0 );

get_opengl_error();

/*
* MAIN LOOP
*/

the_clock.restart();

glEnable( GL_TEXTURE_2D );

glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, tex );

while( true )
{
/*
* Handle events
*/

while( the_window.pollEvent( the_event ) )
{
if( the_event.type == sf::Event::Closed )
{
the_window.close();
exit( 0 );
}
}

/*
* DRAW RESULT
*/

draw_quad();

/*
* Show the result
*/

the_window.display();

frames++;

if( the_clock.getElapsedTime().asMilliseconds() > 1000.0f )
{
int timepassed = the_clock.getElapsedTime().asMilliseconds();
fps = 1000.0f / ( ( float ) timepassed / ( float ) frames );
std::cout << "FPS: " << fps << " Time: " << ( float ) timepassed / ( float ) frames << "\n";
frames = 0;
timepassed = 0;
the_clock.restart();
}
}

return 0;
}

void get_opengl_error( bool ignore )
{
bool got_error = false;
GLenum error = 0;
error = glGetError();
std::string errorstring = "";

while( error != GL_NO_ERROR )
{
if( error == GL_INVALID_ENUM )
{
//An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: invalid enum...\n";
got_error = true;
}

if( error == GL_INVALID_VALUE )
{
//A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: invalid value...\n";
got_error = true;
}

if( error == GL_INVALID_OPERATION )
{
//The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: invalid operation...\n";
got_error = true;
}

if( error == GL_STACK_OVERFLOW )
{
//This command would cause a stack overflow. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: stack overflow...\n";
got_error = true;
}

if( error == GL_STACK_UNDERFLOW )
{
//This command would cause a stack underflow. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: stack underflow...\n";
got_error = true;
}

if( error == GL_OUT_OF_MEMORY )
{
//There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.
errorstring += "OpenGL error: out of memory...\n";
got_error = true;
}

if( error == GL_TABLE_TOO_LARGE )
{
//The specified table exceeds the implementation's maximum supported table size. The offending command is ignored and has no other side effect than to set the error flag.
errorstring += "OpenGL error: table too large...\n";
got_error = true;
}

error = glGetError();
}

if( got_error && !ignore )
{
std::cerr << errorstring;
the_window.close();
return;
}
}





Thankyou! I'll try dloading SFML and giving it a bash. Respect!
Advertisement
One thing is, I really need to get something working with shaders, in the long run it is obviously more flexible for me to do so and immediate mode is deprecated anyway. I'll keep trying!
So as a further note, is there a debug tool available that can check the contents of textures/video memory? I'm not sure if there is a problem with rendering to a texture or something happening to the texture (somehow) between the render to the framebuffer and the render to the full screen quad

So as a further note, is there a debug tool available that can check the contents of textures/video memory? I'm not sure if there is a problem with rendering to a texture or something happening to the texture (somehow) between the render to the framebuffer and the render to the full screen quad

google: gDEBugger

One thing is, I really need to get something working with shaders, in the long run it is obviously more flexible for me to do so and immediate mode is deprecated anyway. I'll keep trying!

ok, it shouldn't be much harder than immediate mode, in fact I myself use fbos with shaders. Just make sure your fbo setup is correct (see my little example) then set up your shaders (load them, bind attributes, uniforms, frag data locations, pass uniforms) then proceed with rendering as usual. Then you just have to display the result (the texture). You can check with gDEBugger if you do render to the texture successfully, and if you do then maybe you are not rendering the result correctly. Or the other way round.
gDebugger is realllllly awesome thanks!

Additionally, I have solved my issue....kind of!

I only swapped some lines of code from


glGenRenderbuffers(1,&fboData.depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER,fboData.depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,fboData.depthWidth,fboData.depthHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,fboData.depthBuffer);

glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,fboData,texID,0);



to


glGenRenderbuffers(1,&fboData.depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER,fboData.depthBuffer);

glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,fboData.depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,fboData.depthWidth,fboData.depthHeight);

glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,fboData.texID,0);


and it kind of works....

Well. What happens is my teapot is now rendered to the screen, but with no movement what so ever. No translation takes place, so no animation is visible! I don't understand it...
I don't understand it either smile.png
maybe you don't transform your vertices? (no matrix multiplication in your shaders...)
but in my setup I do it the other way round, renderbufferstorage and then framebufferrenderbuffer.

I took an in-depth look at your code as I had some time for it and I'd do it like this:
void FrameBufferObject(FBO& fboData,GLenum minFilter,GLenum magFilter)
{
glGenFramebuffers(1,&fboData.handle);
glBindFramebuffer(GL_FRAMEBUFFER,fboData.handle);

GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1,drawBufs);


glGenTextures(1,&fboData.textureData.texID);
glBindTexture(GL_TEXTURE_2D,fboData.textureData.texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

//There is difference between gl_rgba8 and gl_rgba look it up!
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,fboData.depthWidth,fboData.depthHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);

glGenRenderbuffers(1,&fboData.depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER,fboData.depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,fboData.depthWidth,fboData.depthHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,fboData.depthBuffer);

glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,fboData.textureData.texID,0);

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout<<"problem with framebuffer!";
else
std::cout<<"framebuffer ok! smile.png";

glBindFramebuffer(GL_FRAMEBUFFER,0);
}

also don't forget to set the frag data location for
out vec3 color;

in your pixel shaders. This might not be important now, but it may be later.

maybe you don't transform your vertices? (no matrix multiplication in your shaders...)


If I comment out the call to render the texture to the screen and comment out the call to BindFrameBuffer in the teapot drawing code the teapot renders to screen rotating fine, so my vertex program for the teapot is ok.

The weirdest part is if I comment out


GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1,drawBufs);


and change

layout(location=0) out vec3 color;

to

out vec3 color;

in the framebuffer setup code it still renders a static teapot as a texture no problem, and checking in GDebugger the texture is rendering ok?!?! There is something very strange here. My Complete code is available here:


#include "..\shared\Includes.h"
#include "..\shared\ShaderUtilities.h"
#include "Texture1.h"
#include "Cube.h"
#include "Teapot.h"
#include "common/shader.hpp"
#include "common/texture.hpp"
#include "common/controls.hpp"
#include "common/objloader.hpp"
#include "common/vboindexer.hpp"
void Render();

GLuint renderProgram,textureProgram,textureUniform;
GLuint MVPMatrixUniform;
Texture testTexture;
GLuint vertexbuffer;
GLuint uvbuffer;
GLuint normalbuffer;
GLuint elementbuffer;

glm::mat4 perspMatrix,MVPMatrix,camMatrix,scaleMatrix,transformMatrix;
VBOTeapot* teapot;
FBO frameBuf;
bool res;
std::vector<unsigned short> indices;
std::vector<glm::vec3> indexed_vertices;
std::vector<glm::vec2> indexed_uvs;
std::vector<glm::vec3> indexed_normals;
// Read our .obj file
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
const std::string strVertexShaderFile1 = "render.vp";
const std::string strFragmentShaderFile1 = "render.fp";
const std::string strVertexShaderFile2 = "texture.vp";
const std::string strFragmentShaderFile2 = "texture.fp";

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Function prototypes!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void InitVertexBuffer();
GLvoid Reshape(GLsizei width,GLsizei height);
void InitGL();
void DrawGLScene();
void Update();
static const GLfloat g_quad_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLuint quad_vertexbuffer;

int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(640,480);
glutInitWindowPosition(0,0);
glutCreateWindow("ArcSynth shizznit");
GLenum err = glewInit();
if (GLEW_OK != err)
{
return 1;
}
//int things for this app
InitGL();
//callback funcs
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(Reshape);
glutMainLoop();
glDeleteTextures(1,&frameBuf.texID);
glDeleteBuffers(1,&frameBuf.handle);
delete teapot;
return 0;
}

void InitVertexBuffer()
{
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
}

GLvoid Reshape(GLsizei width,GLsizei height)
{
if(height == 0)
height = 1;

glViewport(0,0,width,height);
//glMatrixMode(GL_PROJECTION);
//glLoadIdentity();

//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
}
void InitProgramSpecificData()
{
MVPMatrixUniform = glGetUniformLocation(renderProgram,"MVPMatrix");
ZeroMemory(&frameBuf,sizeof(frameBuf));
frameBuf.depthWidth = 640;
frameBuf.depthHeight = 480;

FrameBufferObject(frameBuf,GL_NEAREST,GL_NEAREST);
perspMatrix = glm::perspective(45.0f,1.0f,0.2f,600.0f);

teapot = new VBOTeapot(8.0f,glm::translate(0.0f,0.0f,0.0f));
camMatrix = glm::lookAt(glm::vec3(0.0f,2.0f,-7.0f),
glm::vec3(0.0f,2.0f,0.0f),
glm::vec3(0.0f,1.0f,0.0f));
InitVertexBuffer();


}
void InitGL(GLvoid)
{
glShadeModel(GL_SMOOTH);
glClearColor(0.5f,0.0f,0.0f,0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_MULTISAMPLE);
InitVertexBuffer();
std::vector<GLchar*> attribs;
attribs.push_back("position");
InitShaderProgram(ReadFile(strVertexShaderFile1),ReadFile(strFragmentShaderFile1),renderProgram,attribs);
InitShaderProgram(ReadFile(strVertexShaderFile2),ReadFile(strFragmentShaderFile2),textureProgram,attribs);
InitProgramSpecificData();

}

void Update()
{
static float angle = 0.0f;
angle += 0.05f;
if(angle > 360.0f)
angle = 0.0f;
glm::mat4 rotateMatrix = glm::rotate(angle,0.0f,1.0f,0.0f);
transformMatrix = rotateMatrix * glm::rotate(-90.0f,1.0f,0.0f,0.0f);
}
void RenderToTexture()
{
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT );
glUseProgram(renderProgram);
glUniformMatrix4fv(MVPMatrixUniform,1,GL_FALSE,&MVPMatrix[0][0]);
//set variables for the fbo
glBindFramebuffer(GL_FRAMEBUFFER,frameBuf.handle);
glViewport(0,0,640,480);
glEnableVertexAttribArray(0);
teapot->render();
glUseProgram(0);
glDisableVertexAttribArray(0);
glBindFramebuffer(GL_FRAMEBUFFER,0);
//glBindTexture(GL_TEXTURE_2D,0);
}
void DrawTextureToQuad()
{
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT );
glViewport(0,0,640,480);
glUseProgram(textureProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,frameBuf.texID);
GLuint texID = glGetUniformLocation(textureProgram, "renderedTexture");
glUniform1i(texID,0);
glEnableVertexAttribArray(0);


//Render to the screen
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !

glDrawArrays(GL_TRIANGLES, 0, 6); // From index 0 to 3 -> 1 triangle
glDisableVertexAttribArray(0);
glUseProgram(0);
}
void DrawGLScene(GLvoid)
{
MVPMatrix = perspMatrix * camMatrix * transformMatrix;
Update();
RenderToTexture();
DrawTextureToQuad();

glutSwapBuffers();
glutPostRedisplay();
}


with framebuffer init code:


void FrameBufferObject(FBO& fboData,GLenum minFilter,GLenum magFilter)
{

glGenFramebuffers(1,&fboData.handle);
glBindFramebuffer(GL_FRAMEBUFFER,fboData.handle);
//GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
//glDrawBuffers(1,drawBufs);
glGenTextures(1,&fboData.texID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,fboData.texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,minFilter);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,magFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,fboData.depthWidth,fboData.depthHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,fboData.texID,0);
glGenRenderbuffers(1,&fboData.depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER,fboData.depthBuffer);
//glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT,fboData.depthWidth,fboData.depthHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,fboData.depthBuffer);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout<<"problem with framebuffer!";
else
std::cout<<"framebuffer ok! :)";

glBindRenderbuffer(GL_RENDERBUFFER,0);
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
If you want to download the whole project and try it yourself please look here:

http://www.mediafire.com/?cezo2t1knpfype1
can you please upload glbatch.h and gltools.h as well?

This topic is closed to new replies.

Advertisement