GBuffer and PBuffer questions

Hello
I’ve read this article trying to understand how buffers work in opengl.
http://www710.univ-lyon1.fr/~jciehl/Public/educ/GAMA/2007/Deferred_Shading_Tutorial_SBGAMES2005.pdf

While it explains very well the tehniques use for deferred lighting it doesn’t explain how to create those buffers and how to use them (select them as render targets).
I’ve tried googleing for “opengl buffer” but that leads to questions about how the build in depth buffer works.
From what I can think of I have to create a buffer myself and use it for those rendering processes. The things I don’t know are how to create it and how to set it as a render target.(and if posibly how to render normal,diffuse,specular and depth in the same pass).
Can anyone point me to some info on this?

If you can, use framebuffer objects (FBO) instead of pbuffers. The main drawback of a pbuffer is it requires to create a separate OpenGL context.

(just to be sure I’m not confusing you, pbuffers are not PBO (pixel buffer objects), and PBOs are not FBOs)

Here is a good tutorial for FBO creation and concepts:
http://www.songho.ca/opengl/gl_fbo.html

For detail reference, here is the FBO extension:
http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt

Here is a more recent FBO extension (slightly different)
http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt

In the case of FBO, you can just create a texture for each buffer (normal,diffuse,specular,depth) and attach each of them to a attachment point of the FBO.

You can draw in several buffers at the same time with glDrawBuffers() command:

see extension ARB_draw_buffers (or OpenGL spec>=2.0):
http://www.opengl.org/registry/specs/ARB/draw_buffers.txt

Example:
// Tell that subsequent drawing operations will happen in color attachment 2 and 3 at the same time:
// color attachement 2 will be drawbuffer0
// color attachement 3 will be drawbuffer1
GLenum bufs[2]={GL_COLOR_ATTACHMENT2,GL_COLOR_ATTACHMENT3};
void glDrawBuffers(2,bufs);

In a fragment shader you can write to several color buffers at the same time by using gl_FragData instead of gl_FragColor with:

// draw in drawbuffer 0 (color attachment2 in our case)
gl_FragData[0].rgba=vec4(0.2,0.1,0.6,1.0);
// draw in drawbuffer 1 (color attachment3 in our case)
gl_FragData[1].rgba=vec4(0.5,0.3,0.2,0.1);

Haven’t read them yet (going to right now) but from waht I can see you are a lifesaver :slight_smile:
Thank you! Thank you very much

I still have little problem

I have this code here to initialize a buffer


CBuffer::CBuffer(int Width, int Height, int type)
{
	// Create the frame buffer
	glGenFramebuffersEXT(1, &this->bufferID);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->bufferID);
	if(type & BUFFER_DEPTH)
	{
		glGenTextures(1, &this->depth);
		glBindTexture(GL_TEXTURE_2D, this->depth);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		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_GENERATE_MIPMAP, GL_TRUE); 
		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,GL_ALPHA, GL_UNSIGNED_BYTE, 0);
		glBindTexture(GL_TEXTURE_2D, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, color, 0);
		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	}
	if(type & BUFFER_COLOR)
	{
		glGenTextures(1, &this->color);
		glBindTexture(GL_TEXTURE_2D, this->color);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		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_GENERATE_MIPMAP, GL_TRUE); 
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, color, 0);
	}
	if(type & BUFFER_NORMAL)
	{
		glGenTextures(1, &this->aux0);
		glBindTexture(GL_TEXTURE_2D, this->aux0);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		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_GENERATE_MIPMAP, GL_TRUE); 
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
		glBindTexture(GL_TEXTURE_2D, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,GL_TEXTURE_2D, aux0, 0);
		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	}
	

	width =Width;
	height=Height;

	// check FBO status
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->bufferID);
    int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status)
    {
    case GL_FRAMEBUFFER_COMPLETE_EXT:
		fprintf(GetCurrentEngine()->logFile, "Framebuffer complete.
");
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: Attachment is NOT complete." );
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: No image is attached to FBO." );
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: Attached images have different dimensions.");
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: Color attached images have different internal formats." );
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: Draw buffer.
");
        break;

    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Framebuffer incomplete: Read buffer.
");
        break;

    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Unsupported by FBO implementation.
");
        break;

    default:
        fprintf(GetCurrentEngine()->logFile,"[ERROR] Unknow error.
");
        break;
    }
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

Somehow I get “[ERROR] Framebuffer incomplete: Attachment is NOT complete.” in the log.
I have no ideea why that happens. I preety much followed the tutorials. I don’t even use float textures (those don’t work on some hardware).

I’ve tryied almost everything I found on the internet and nothing…
I even have a source that’s supposed to be working(I also have the binary and it works).

You didn’t say where the error message happen (in case of depth? color? normal?).

I think you cannot call the following line:
glBindTexture(GL_TEXTURE_2D, 0);
and try to attach GL_TEXTURE_2D to the FBO afterwards.
you have to attach first and then you are good for unbinding the texture target and texture object.

Also, it seems that your constructor is creating a FBO with just a single attachment (chosen by the third argument “type”). Is it what you really want to do?

If you look at the if condition is with a binary and. I call it with the type argument being “BUFFER_COLOR|BUFFER_DEPTH|BUFFER_NORMAL”(1|2|4).
So I call all of them and thus in my log I get a message at every step.
right now in the log there are
“[ERROR] Framebuffer incomplete: No image is attached to FBO.
[ERROR] Framebuffer incomplete: No image is attached to FBO.
[ERROR] Framebuffer incomplete: Attachment is NOT complete.
[ERROR] Framebuffer incomplete: Attachment is NOT complete.
[ERROR] Framebuffer incomplete: Attachment is NOT complete.”
Also doing the texture/renderbuffer bind thing afterwards won’t fix the problem and on some examples I see they unbind the texture before they bind it in the FBO.

Don’t you have any error returned by glGetError() after the following line in depth section?

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,GL_ALPHA, GL_UNSIGNED_BYTE, 0);

You should have GL_DEPTH_COMPONENT not GL_ALPHA.

Still on the depth section, you use “this->color” instead of “this->depth

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, color, 0);

I’d be dammned
“glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);” was invalid because width was 800 and height 600.
I tried with 512X512 and it works. So then I guess all textures have to have a size the power of 2?
I’d like my buffer to have 800X600 dimensions (or rezolution like sizes) since I’d like to use it for the deferred shading.
Is there any workaround?

I remember having an issue like that with a nVidia GeForce FX 5200: it would support non-power-of-two (NPOT) textures, would support FBO but would not support NPOT textures as a color attachment of an FBO. On top of my head the reported error was GL_FRAMEBUFFER_UNSUPPORTED_EXT. For this old card I would have to use rectangular textures (see extension GL_ARB_texture_rectangle, mipmapping is not supported and texel access happens with unnormalized texture coordinates).

I have no problem with nVidia GeForce>=6.

Hence my questions now:

  1. Which OS do you have?
  2. Which graphics card do you have?
  3. Which driver version do you have?

For question 3,
a. on Linux, type
$ glxinfo
b. on Mac OS X, with Xcode installed, go to Macintosh HD->Developer->Applications->Graphic Tools->OpenGL Driver Monitor.app->Monitors->Renderer Info-><name of the OpenGL driver>
c. on Windows, download and use GLview http://www.realtech-vr.com/glview

I run Windows XP sp 3 and I have a nvidia 8600GM (laptop).
The drivers are the latest from the dell page but those are quite old :expressionless: and usually don’t get updates…
Now since I’ll only use buffers for the actuall screen and nothing else I guess no mipmaps and linear texture won’t affect me at all.
I’ll take a look at that extension :slight_smile:
Thank you.

EDIT:
After I say this I might get to be the comunity’s buffon but I had width and height from the class and Width and Height as paramenters. I used the ones from the class which weren’t initialized (they got initilized at the end) so basically after I modified this it works perfect on both my computers. :slight_smile: Onwards to the deferred shader :slight_smile: