Framebuffer object + view problems

Hi there. I still haven’t used framebuffer objects and textures (to be drawn on a quad) long enough to understand exactly what wrong I am doing.

I managed to get it to work once before when I did a multipass rendering with a friend…but the problem then was that the view got extremely zoomed in (both the viewable objects and the skybox I’m inside).

I tried using the same code again with some minor modifications and tried to render my scene to a quad that is drawn (I bind a variable called img0 to the quad which is the texture) just to see if it works (the result should be the exact same scene I had before I used any framebuffer objects and alike) and I get the same problem again…skybox and teapots become zoomed in. I’m not sure what wrong I’m doing since I’m quite new to this.

Any help or suggestion is appreciated. Thanks

Here’s the code:

#include <stdlib.h>


#include <GL/glew.h>

#include <GL/gl.h>

#include <GL/glut.h>


#include <stdio.h>
#include <time.h>
#include <sys/stat.h>

#include <math.h>

#include <iostream>



GLuint texture[5];

GLuint windowWidth = 700;
GLuint windowHeight = 700;

int mouse_old_x; //Position of the mouse
int mouse_old_y; // Position of the mouse

bool rotate; 

static float xRot; 
static float yRot; 

GLfloat whiteSpecularLight[] = {1.0, 1.0, 1.0};
GLfloat whiteSpecularMaterial[] = {1.0, 1.0, 1.0};

GLfloat mShininess[] = {50};

GLint programObj1;
GLint programObj6;

GLint location_testTexture;
GLint location_time;
GLint location_center;

GLuint fbo;  
GLuint depthbuffer;

GLuint img0; //First offscreen render
GLuint img1; //Second offscreen render

float focalDistance = -7.0f;
float focalRange = 6.0f;

GLint loc;

//Function prototypes

void light(void);
void skybox(void);
void teapots(void);
void drawQuad(void);
void init(void);

//Read shader files

char* readShaderFile(const char *filename) {
  FILE *file;
  struct stat st;
  
  file = fopen(filename, "r");
  
  if(file == NULL){
    fprintf( stderr, "ERROR: Cannot open shader file!");
    return 0;
  }
  
  stat(filename,&st);
  
  int bytesinfile = st.st_size;
  char *buffer = (char*)malloc(bytesinfile+sizeof(char));
  int bytesread = fread( buffer, 1, bytesinfile, file);
  buffer[bytesread] = 0; // Terminate the string with 0
  fclose(file);
  
  return buffer;
}

//Create shaders

void createShaders() {
  std::cout<< "Hej create shaaaaaaaaaaaaaaders" << std::endl;
  GLint vertexShader1 = glCreateShader(GL_VERTEX_SHADER); //Create vertex shader
  GLint vertexShader6  = glCreateShader(GL_VERTEX_SHADER);
  
  const char *vertexAssembly1 = readShaderFile("first.vert"); //Read vertex shader file
  const char *vertexAssembly6 = readShaderFile("fifth.vert");
  glShaderSource( vertexShader1, 1, &vertexAssembly1, NULL );
  glShaderSource( vertexShader6, 1, &vertexAssembly6, NULL );
  glCompileShader( vertexShader1);
  glCompileShader( vertexShader6);
  free((void *)vertexAssembly1);
  free((void *)vertexAssembly6);
  
  GLint isCompiled;
  glGetShaderiv( vertexShader1, GL_COMPILE_STATUS, &isCompiled );
 
  if(isCompiled == GL_FALSE){
    char str[256];
    glGetShaderInfoLog(vertexShader1, 256, NULL, str);
    fprintf( stderr, "Vertex shader compile error: %s
", str);
  }

  glGetShaderiv( vertexShader6, GL_COMPILE_STATUS, &isCompiled );

  if(isCompiled == GL_FALSE){
    char str[256];
    glGetShaderInfoLog(vertexShader6, 256, NULL, str);
    fprintf( stderr, "Vertex shader compile error: %s
", str);
  }
  
  
  GLint fragmentShader1 = glCreateShader( GL_FRAGMENT_SHADER ); //Create fragmet shader
  GLint fragmentShader6 = glCreateShader( GL_FRAGMENT_SHADER );
  
  const char *fragmentAssembly1 = readShaderFile( "first.frag" ); //Read fragment shader file
  const char *fragmentAssembly6 = readShaderFile( "renderblur.frag" );
  glShaderSource( fragmentShader1, 1, &fragmentAssembly1, NULL );
  glShaderSource( fragmentShader6, 1, &fragmentAssembly6, NULL );
  glCompileShader( fragmentShader1 );
  glCompileShader( fragmentShader6 );
  free((void *)fragmentAssembly1);
  free((void *)fragmentAssembly6);
  
  glGetShaderiv( fragmentShader1, GL_COMPILE_STATUS, &isCompiled );
  
  if(isCompiled == GL_FALSE){
    char str[256];
    glGetShaderInfoLog( fragmentShader1, 256, NULL, str );
    fprintf( stderr, "Fragment shader compile error: %s
", str );
  }

  glGetShaderiv( fragmentShader6, GL_COMPILE_STATUS, &isCompiled );
  if(isCompiled == GL_FALSE){
    char str[256];
    glGetShaderInfoLog( fragmentShader6, 256, NULL, str );
    fprintf( stderr, "Fragment shader compile error: %s
", str );
  }
  
  programObj1 = glCreateProgram();
  programObj6 = glCreateProgram();
  glAttachShader( programObj1, vertexShader1 );
  glAttachShader( programObj6, vertexShader6 );
  glAttachShader( programObj1, fragmentShader1 );
  glAttachShader( programObj6, fragmentShader6 );
  
  glLinkProgram( programObj1 );
  glLinkProgram( programObj6 );
  GLint isLinked;
  glGetProgramiv( programObj1, GL_LINK_STATUS, &isLinked );
  
  if( isLinked == GL_FALSE ){
    char str[256];
    glGetProgramInfoLog( programObj1, 256, NULL, str );
    fprintf( stderr, "Program object linking error: %s
", str );
  }

  glGetProgramiv( programObj6, GL_LINK_STATUS, &isLinked );
  
  if( isLinked == GL_FALSE ){
    char str[256];
    glGetProgramInfoLog( programObj6, 256, NULL, str );
    fprintf( stderr, "Program object linking error: %s
", str );
  }
}

//Method for deleting texture once they've been used


void FreeTexture( GLuint texture )

{

  glDeleteTextures( 1, &texture );

}


//Loading the textures that will be used for the skybox


GLuint LoadTexture( const char * filename, int width, int height )

{

    GLuint texture;

    unsigned char * data;

    FILE * file;



    //This code read the raw files.

    file = fopen( filename, "rb" );

    if ( file == NULL ) return 0;

    data = (unsigned char *)malloc( width * height * 3 );

    fread( data, width * height * 3, 1, file );

    fclose( file );



    glGenTextures( 1, &texture ); //Generate texture

    glBindTexture( GL_TEXTURE_2D, texture ); //Bind texture to texture array declared above

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //texture environment parameters



    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );



    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);



    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);



    free( data ); //free the texture

    return texture; //return whether it was successfull

}


//Keyboard controls


void keyboard(unsigned char key, int x, int y)

{

	if(key==27) //27 is ASCI-code for ESC key

	{

		exit(0); //Exit the program

	}

}

void processMouse(int button, int state, int x, int y) 
{
	if ((state == GLUT_DOWN) && (button == GLUT_LEFT_BUTTON))
	{
	      rotate=true;
	}else
        {
              rotate=false;
        }
mouse_old_x =x;
mouse_old_y =y;

}

void processMouseActiveMotion(int x, int y) 
{
float weight =0.2;
	if(rotate) {
        xRot += (x-mouse_old_x) * weight;
        yRot += (y-mouse_old_y) * weight;
        }

mouse_old_x =x;
mouse_old_y =y;
}
		

void initFbo()
{
	//Create a framebuffer object
	glGenFramebuffersEXT(1, &fbo); //Frame buffer
	glGenRenderbuffersEXT(1, &depthbuffer); //render buffer
	glGenTextures(1, &img0); //texture
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fbo);

	//initialize texture
	glBindTexture(GL_TEXTURE_2D, img0);
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,windowWidth,windowHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);

	//texture parameters
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  	glGenerateMipmapEXT(GL_TEXTURE_2D);
	
	//attach texture to framebuffer color buffer
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, img0,0);
	
	//initialize depth renderbuffer
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,windowWidth,windowHeight);

	//attach renderbuffer to framebuffer depth buffer
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,depthbuffer);
}

void firstPass()
{
	init();
	glEnable(GL_TEXTURE_2D);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
	glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT);
	glViewport(0,0,windowWidth, windowHeight);
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glActiveTexture(GL_TEXTURE0);
	glLoadIdentity();
  	//glOrtho(0.0,1.0,0.0,1.0,0.0,1.0);
	//glUseProgram(programObj1);
	//loc = glGetUniformLocation(programObj1, "focalDistance");
	//glUniform1f(loc, focalDistance);
	//loc = glGetUniformLocation(programObj1, "focalRange");
	//glUniform1f(loc, focalRange);
	light();
	skybox();

	teapots();
}

void blurTestPass()
{
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_COLOR_MATERIAL);
		
	glPopAttrib();
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	glDrawBuffer(GL_BACK);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glLoadIdentity();
  	glOrtho(0.0,1.0,0.0,1.0,0.0,1.0); //Testa ta bort sen
	glColor4f(1.0,1.0,1.0,0.0);
	glBindTexture(GL_TEXTURE_2D, img0);
	glUseProgram(programObj6);
	drawQuad();
	glDisable(GL_TEXTURE_2D);
	glUseProgram(0);
}


void skybox()

{   
    float quadSize = 1000.0; //Size of each quad

    glPushMatrix();

	

    glLoadIdentity(); //Loading identity matrix


    gluLookAt(0.0,0.0,0.0,0.0,0.0,1.0,0.0,-1.0,0.0); //Setting up the camera for the scene. The cameras position is located in origo. This is because we want to be inside the skybox.



    glPushAttrib(GL_ENABLE_BIT);

    glEnable(GL_TEXTURE_2D);

    glDisable(GL_LIGHTING);


    glColor4f(1,1,1,1); //Set color for the quad



    //Create and bind a texture for the front quad

    glBindTexture(GL_TEXTURE_2D, texture[0]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex3f(  quadSize, -quadSize, -quadSize );

        glTexCoord2f(1, 0); glVertex3f( -quadSize, -quadSize, -quadSize );

        glTexCoord2f(1, 1); glVertex3f( -quadSize,  quadSize, -quadSize );

        glTexCoord2f(0, 1); glVertex3f(  quadSize,  quadSize, -quadSize );

    glEnd();



    //Create and bind a texture for the left quad

    glBindTexture(GL_TEXTURE_2D, texture[1]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex3f(  quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 0); glVertex3f(  quadSize, -quadSize, -quadSize );

        glTexCoord2f(1, 1); glVertex3f(  quadSize,  quadSize, -quadSize );

        glTexCoord2f(0, 1); glVertex3f(  quadSize,  quadSize,  quadSize );

    glEnd();



    //Create and bind a texture for the back quad

    glBindTexture(GL_TEXTURE_2D, texture[2]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex3f( -quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 0); glVertex3f(  quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 1); glVertex3f(  quadSize,  quadSize,  quadSize );

        glTexCoord2f(0, 1); glVertex3f( -quadSize,  quadSize,  quadSize );



    glEnd();



    //Create and bind a texture for the right quad

    glBindTexture(GL_TEXTURE_2D, texture[3]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex3f( -quadSize, -quadSize, -quadSize );

        glTexCoord2f(1, 0); glVertex3f( -quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 1); glVertex3f( -quadSize,  quadSize,  quadSize );

        glTexCoord2f(0, 1); glVertex3f( -quadSize,  quadSize, -quadSize );

    glEnd();



    //Create and bind a texture for the top quad

    glBindTexture(GL_TEXTURE_2D, texture[4]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 1); glVertex3f( -quadSize,  quadSize, -quadSize );

        glTexCoord2f(0, 0); glVertex3f( -quadSize,  quadSize,  quadSize );

        glTexCoord2f(1, 0); glVertex3f(  quadSize,  quadSize,  quadSize );

        glTexCoord2f(1, 1); glVertex3f(  quadSize,  quadSize, -quadSize );

    glEnd();



    //Create and bind a texture for the bottom quad

    glBindTexture(GL_TEXTURE_2D, texture[5]);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0); glVertex3f( -quadSize, -quadSize, -quadSize );

        glTexCoord2f(0, 1); glVertex3f( -quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 1); glVertex3f(  quadSize, -quadSize,  quadSize );

        glTexCoord2f(1, 0); glVertex3f(  quadSize, -quadSize, -quadSize );

    glEnd();



    // Restore enable bits and matrix

    glPopAttrib();

    glPopMatrix();



    //Return states

    glDisable(GL_TEXTURE_2D);

}

//Enable lighting and color material of objects

void init()
{
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
}

//Lighting properties

void light()
{
	glLightfv(GL_LIGHT0, GL_SPECULAR, whiteSpecularLight);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecularMaterial);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mShininess);
}


//Render teapots with a rotational value depending on the movement of the mouse


void teapots()

{

	//Blue teapot

	glPushMatrix();

	glColor4f(0.64,0.67,0.84,1.0);

	glTranslatef(3.0,0.0,-14.0);
	glRotatef(xRot,0.0,1.0,0.0);
	glRotatef(yRot,1.0,0.0,0.0);

	glutSolidTeapot(1);

	glPopMatrix();

	

	//Pink teapot

	glPushMatrix();

	glColor4f(0.79,0.63,0.72,1.0);

	glTranslatef(1.0,0.0,-11.0);
	glRotatef(xRot,0.0,1.0,0.0);
	glRotatef(yRot,1.0,0.0,0.0);

	glutSolidTeapot(1);

	glPopMatrix();



	//Green teapot

	glPushMatrix();

	glColor4f(0.64,0.67,0.49,1.0);

	glTranslatef(-1.0,0.0,-7.0);
	glRotatef(xRot,0.0,1.0,0.0);
	glRotatef(yRot,1.0,0.0,0.0);

	glutSolidTeapot(1);

	glPopMatrix();
	
}

void drawQuad(void)
{
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f);
		glVertex2d(0, 0);
		glTexCoord2f(1.0f, 0.0f);
		glVertex2d(1, 0);
		glTexCoord2f( 1.0f, 1.0f);
		glVertex2d(1, 1);
		glTexCoord2f(0.0f, 1.0f);
		glVertex2d(0, 1);
	glEnd();
}



void display()

{

	glClearColor(0.0,0.0,0.0,1.0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
	glClearDepth(1);
	glLoadIdentity();
	firstPass();
	blurTestPass();

	glutSwapBuffers(); //Swap between the two buffers

}



void reshape(int w, int h)

{

	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0,(GLfloat)w/(GLfloat)h,0.1,10000.0);
	glMatrixMode(GL_MODELVIEW); 
}




int main(int argc, char **argv)

{

	glutInit(&argc, argv); //Initialize GLUT

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA| GLUT_DEPTH); //Use a double buffer when displaying frames.

	glutInitWindowSize(windowWidth, windowHeight); 

	glutInitWindowPosition(100, 100); 

	

	glutCreateWindow("Test"); 
	init();
	glewInit();
	initFbo();


	glutDisplayFunc(display); 
	glutIdleFunc (display);


	glutReshapeFunc(reshape); 

	glutMouseFunc(processMouse);
	glutMotionFunc(processMouseActiveMotion);
	

	texture[0] = LoadTexture( "skylf.raw", 512, 512 );
	texture[1] = LoadTexture( "skyft.raw", 512, 512 );

	texture[2] = LoadTexture( "skyrt.raw", 512, 512 );
	texture[3] = LoadTexture( "skybk.raw", 512, 512 );
	texture[4] = LoadTexture( "skydn.raw", 512, 512 );

	texture[5] = LoadTexture( "skyup.raw", 512, 512 );

	glutKeyboardFunc(keyboard);



	glutMainLoop(); //Start the OpenGL loop-cycle



	for(int i=0; i<6; i++)

	{

		FreeTexture(texture[i]);

	}

	

	return 0;

}

First thing that popped into my mind was wrong glViewport. Looking at your code, you set it when rendering to FBO, but you don’t reset it when rendering to window. You need to add a glViewport to your blurTestPass.

And you probably don’t want to be mucking with it directly in reshape(). Store it off and use it in blurTestPass later.

Also, in your blurTestPass, you’re “trying” to set up an orthographic projection (glOrtho), but you forgot to flip the MatrixMode to PROJECTION. It needs to live there, not MODELVIEW.

I’m a little bit confused, just like you said I don’t use any glViewport when actually rendering to the window. Do you mean that I should add the exact same glViewport that is set for my FBO? If so wouldn’t it be enough by just moving the PopAttrib to the end of blurTestPass?

Or do you mean that I should move the viewport I declare in my reshape function to the blurTestpass? If so should I just put a new PushAttrb and PopAttrb in the blurTestpass?

Also when I putted a glMatrixMode(GL_PROJECTION) right before the ortographic projection the screen turned black instead.

Do whatever viewport makes sense. If your window and your FBO/texture have the same resolution and you want to draw in the same place, then using the same viewport is fine.

If so should I just put a new PushAttrb and PopAttrb in the blurTestpass?

PushAttrib/PopAttrib are deprecated. I wouldn’t start getting used to them.

Also when I putted a glMatrixMode(GL_PROJECTION) right before the ortographic projection the screen turned black instead.

Guess you’ve got other fish to fry then. I’d trace the logic again and do some reading.