I modified a simple program to introduce A strange problem about FBO!

Today , I modified a FBO example from Gamedev, the program is simple,but could introduce my trouble : after GL_COLOR_ATTACHMENT4_EXT, the FBO could not render a texture target correct!

Hope some good guy could run code to see trouble, and could give me some idea to get me out of trouble!

 thanks advanced!
#include <GL/glew.h>
#include <GL/glut.h>

#include <iostream>

GLuint fbo;// Our handle to the FBO
GLuint depthBuffer;// Our handle to the depth render buffer

const int TexNum = 8;
GLuint texID[TexNum];// Our handle to a textures
const int width = 512;// The hight of the texture we'll be rendering to
const int height = 512;		// The width of the texture we'll be rendering to

// Used for drawing the 3D cube with our rendered texture on it
GLfloat	xrot = 0;			// X Rotation
GLfloat	yrot = 0;			// Y Rotation
GLfloat xspeed = 0.2f;		// X Rotation Speed
GLfloat yspeed = 0.1f;		// Y Rotation Speed
GLuint ATTACHMENT_ARRAY[10] ={
	GL_COLOR_ATTACHMENT0_EXT,	GL_COLOR_ATTACHMENT1_EXT,
	GL_COLOR_ATTACHMENT2_EXT,	GL_COLOR_ATTACHMENT3_EXT,
	GL_COLOR_ATTACHMENT4_EXT,	GL_COLOR_ATTACHMENT5_EXT,
	GL_COLOR_ATTACHMENT6_EXT,	GL_COLOR_ATTACHMENT7_EXT,
	GL_COLOR_ATTACHMENT8_EXT,	GL_COLOR_ATTACHMENT9_EXT};
void initFBO()
{
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0f, 0.0f, 0.2f, 0.5f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glViewport(0,0,512,512);

	// Setup our FBO
	glGenFramebuffersEXT(1, &fbo);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

	// Create the render buffer for depth
	glGenRenderbuffersEXT(1, &depthBuffer);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);

	int jx ;
	//initialize texture
	for (jx = 0 ;jx < TexNum;++jx)
	{
		glGenTextures(1, &texID[jx]);
		glBindTexture(GL_TEXTURE_2D, texID[jx]);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		// And attach it to the FBO so we can render to it
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, ATTACHMENT_ARRAY[jx], GL_TEXTURE_2D, texID[jx], 0);
	}

}

void ShutDown(GLvoid)
{
	glDeleteFramebuffersEXT(1, &fbo);
	glDeleteRenderbuffersEXT(1, &depthBuffer);
	for(int jx = 0;jx < TexNum;++jx)
	{
		glDeleteTextures(1,&texID[jx]);
	}

}

void reshape(int w,int h)
{
	glViewport( 0, 0, w, h );
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if ( h==0 )
		gluPerspective(80,(float)w,1.0,5000.0);
	else
		gluPerspective(80,(float)w/(float)h,1.0,5000.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void keyboard(unsigned char key,int x,int y)
{
	switch(key)
	{
	case 27:				// When Escape Is Pressed...
		ShutDown();
		exit(0);			// Exit The Program
		break;
	default:
		break;
	}
}

void idle(void)
{
	glutPostRedisplay();
}
void drawCube(float r,float g,float b)
{
	glClearColor(r, g, b, 0.5f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
	glLoadIdentity();

	glTranslatef(0.0f,0.0f,-2.0f);
	glRotatef(xrot,1.0f,0.0f,0.0f);
	glRotatef(yrot,0.0f,1.0f,0.0f);

	glBegin(GL_QUADS);
	// Front Face
	glColor4f(0.0f,1.0f,0.0f,1.0f);
	glVertex3f(-0.5f, -0.5,  0.5);
	glVertex3f( 0.5, -0.5,  0.5);
	glVertex3f( 0.5,  0.5,  0.5);
	glVertex3f(-0.5,  0.5,  0.5);
	// Back Face
	glColor4f(1.0f,0.0f,0.0f,1.0f);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5,  0.5, -0.5);
	glVertex3f( 0.5,  0.5, -0.5);
	glVertex3f( 0.5, -0.5, -0.5);
	// Top Face
	glColor4f(0.0f,0.0f,1.0f,1.0f);
	glVertex3f(-0.5,  0.5, -0.5);
	glVertex3f(-0.5,  0.5,  0.5);
	glVertex3f( 0.5,  0.5,  0.5);
	glVertex3f( 0.5,  0.5, -0.5);
	// Bottom Face
	glColor4f(0.0f,1.0f,1.0f,1.0f);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f( 0.5, -0.5, -0.5);
	glVertex3f( 0.5, -0.5,  0.5);
	glVertex3f(-0.5, -0.5,  0.5);
	// Right face
	glColor4f(1.0f,1.0f,0.0f,1.0f);
	glVertex3f( 0.5, -0.5, -0.5);
	glVertex3f( 0.5,  0.5, -0.5);
	glVertex3f( 0.5,  0.5,  0.5);
	glVertex3f( 0.5, -0.5,  0.5);
	// Left Face
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	glVertex3f(-0.5, -0.5, -0.5);
	glVertex3f(-0.5, -0.5,  0.5);
	glVertex3f(-0.5,  0.5,  0.5);
	glVertex3f(-0.5,  0.5, -0.5);
	glEnd();

}

void drawTextureCube(GLuint tex)
{
	glBindTexture(GL_TEXTURE_2D, tex);
	glBegin(GL_QUADS);
	// Front Face
	glNormal3f( 0.0f, 0.0f, 1.0);
	glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5,  0.5);
	glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5, -0.5,  0.5);
	glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5,  0.5,  0.5);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5,  0.5,  0.5);
	// Back Face
	glNormal3f( 0.0f, 0.0f,-1.0);
	glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5, -0.5);
	glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5,  0.5, -0.5);
	glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5,  0.5, -0.5);
	glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5, -0.5);
	// Top Face
	glNormal3f( 0.0f, 1.0, 0.0f);
	glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5,  0.5, -0.5);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5,  0.5,  0.5);
	glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5,  0.5,  0.5);
	glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5,  0.5, -0.5);
	// Bottom Face
	glNormal3f( 0.0f,-1.0, 0.0f);
	glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, -0.5, -0.5);
	glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5, -0.5, -0.5);
	glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5,  0.5);
	glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5,  0.5);
	// Right face
	glNormal3f( 1.0, 0.0f, 0.0f);
	glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5, -0.5, -0.5);
	glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5,  0.5, -0.5);
	glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5,  0.5,  0.5);
	glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5,  0.5);
	// Left Face
	glNormal3f(-1.0, 0.0f, 0.0f);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, -0.5, -0.5);
	glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5,  0.5);
	glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5,  0.5,  0.5);
	glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5,  0.5, -0.5);
	glEnd();

}
void display(void)
{
	// First we bind the FBO so we can render to it
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

	// Save the view port and set it to the size of the texture
	glPushAttrib(GL_VIEWPORT_BIT);
	glViewport(0,0,width,height);

	// Then render as normal
	// Today's scene is a wonderful multi-coloured spinning cube ;)
	// which we will draw twice, once in one set of colours and once in another
	glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
	drawCube(1.0,0.0,0.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
	drawCube(0.0,1.0,0.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT);
	drawCube(0.0,0.0,1.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT);
	drawCube(1.0,1.0,0.0);

	/////////////// have ERROR  ///////////////
	glDrawBuffer(GL_COLOR_ATTACHMENT4_EXT);
	drawCube(1.0,0.0,1.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT5_EXT);
	drawCube(0.0,1.0,1.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT6_EXT);
	drawCube(1.0,0.50,1.0);
	glDrawBuffer(GL_COLOR_ATTACHMENT7_EXT);
	drawCube(0.50,1.0,1.0);


	// Restore old view port and set rendering back to default frame buffer
	// this resets the drawing destination to GL_BACK so we don't need to do it ourselves
	glPopAttrib();
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	// Now we clear the default frame buffer we are going to render to
	glClearColor(1.0f, 1.0f, 1.f, 0.5f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
	glEnable(GL_TEXTURE_2D);
	// Now we get ready to draw the first cube with the first texture attached
	glLoadIdentity();

	float Z = 5.0;
	glTranslatef(-1.2f,3.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[0]);

	glLoadIdentity();
	glTranslatef(1.2f,3.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[1]);

	glLoadIdentity();
	glTranslatef(-1.2f,1.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[2]);

	glLoadIdentity();
	glTranslatef(1.2f,1.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[3]);
	// Above display result is OK //////////

	// Following display result is ERROR ////
	glLoadIdentity();
	glTranslatef(-1.2f,-1.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[4]);

	glLoadIdentity();
	glTranslatef(1.2f,-1.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[5]);


	glLoadIdentity();
	glTranslatef(-1.2f,-3.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
	drawTextureCube(texID[6]);

	glLoadIdentity();
	glTranslatef(1.2f,-3.0f,-Z);
	glRotatef(-xrot,1.0f,0.0f,0.0f);
	glRotatef(-yrot,0.0f,1.0f,0.0f);
 	drawTextureCube(texID[7]);

	glDisable(GL_TEXTURE_2D);

	xrot+=xspeed;
	yrot+=yspeed;

	glutSwapBuffers ( );
	// Swap The Buffers To Not Be Left With A Clear Screen
}

bool initGLEW()
{
	//glReadBuffer(GL_BACK);

	glewInit();
	if (!glewIsSupported("GL_VERSION_2_0"))
	{
		printf("OpenGL 2.0 not supported
");
		return false;
	}

	return true;
}

int main(int argc, char* argv[])
{
	glutInit(&argc, (char**)argv);
	glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE );
	glutInitWindowSize(800,600);
	glutCreateWindow( "FrameBuffer Object Example 2 - Press ESC to exit" );
	if(!initGLEW())
		exit(2);
	initFBO();
	glutDisplayFunc( display );
	glutReshapeFunc( reshape );
	glutKeyboardFunc( keyboard );
	glutIdleFunc( idle );
	glutMainLoop();
	return 0;
}

You’re probably only allowed to draw to 4 buffers. You can query this by:

GLuint maxbuffers;
glGetIntergeri(GL_MAX_DRAW_BUFFERS, &maxbuffers);

The more relevant parameter to check is GL_MAX_COLOR_ATTACHMENTS_EXT. This parameter specifies how many color attachment points are available. It if contains 4, which is very likely, only color attachments from <GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT3_EXT> range are allowed.

Modern cards can render only to 4 render targets maximal (I am not so sure about 8800).

Oh,yes You are right!
I query :glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxbuffers); the result is 4,It is too bad, I need 8; My card is GF6800GT!

thanks CatAtWork 、Komat and Zengar.

And this result produce another question : have another way to “copy” a texture to another texture, beside using glGetTexImage to get target imagedata then using glSubTexImage2D to replace ? I mean direct operation in GPU!

for example, in for loop, I use FBO GL_COLOR_ATTACHMENT2_EXT capture frame buffer to Texture Object render_texture , then “copy” to Texture Object result_texturei ?

Draw the texture to an FBO and then copy it to the textures using glCopyTexSubImage.

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