Offscreen rendering

I would like to get the contents of the color buffer and depth buffer that would have been displayed but without displaying them. I read that you can use frame buffer objects (FBOs) but all of the FBO examples I saw were talking about textures and all kinds of stuff that I don’t need. I just want to save an image of a very basic model from different viewpoints without displaying it on the screen. Does anyone have an example of that / any examples?

Thanks,

Dave

Hi Dave,

When you create an FBO you have to attach textures and render buffers to it so that you have something to render into. An FBO is just a structure to hold all of those things together.

The minimum useful requirement for an FBO is a layer of some sort to draw into. The easiest way to achieve this is with a texture IMO. Textures can be added for colour and depth layers and so on…

When reading data back from an FBO you actually interrogate the textures which are attached to it.

This is quite a good tutorial IMO…
http://www.gamedev.net/reference/articles/article2331.asp

Hope that helps.

if u want to save only the image on the hard disk that mean that u want to make a transfer from ur graphics card to central memory than to hard disk. if u want to do a simple transfer u have to use the ugly glReadPixels.

to save an image of ur model without displaying ur model on ur screen than u have to comment the line that swap ur buffers(if u are using double buffering) (for ex in SDL comment the line : SDL_GL_SwapBuffers)but now u have to read the Back buffer and not the front buffer using the command glReadBuffer(GL_BACK) before ur glReadPixels,

finally, it is better to use fbo ( best performance)

If I simply don’t swap the buffers, I still have to have an active window, right? What I want is to save the depth buffer of what would have been rendered without even opening a window. I’m looking into FBOs - but they can do that, right?

yes

opengl is not attached to any window or rendering surface , it is a just a library that contain functions to draw objects in 3D space. check ur SDL or glut or Qt or whetever

This is true is theory, but the pixel ownership rule makes that fragile. The non-visible part(s) of the framebuffer is undefined.
Quote from OpenGL FAQ 14.070 :
“If a window is obscured by another window, it doesn’t have to store pixel data for the obscured region. Therefore, a glReadPixels() call can return undefined data for the obscured region.”

The answer : FBO.

i agree with u !
but the question i am asking is the Operating system wich decide not to store pixels or the rendering surface( sdl … ) ?
i think it is sdl no ?

I followed the tutorial scratt gave. There is one part that says to check


	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	
	if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		cout << gluErrorString(status) << endl;
	}

It is returning “no error”, but I guess that is different than “GL_FRAMEBUFFER_COMPLETE_EXT” ?

here is my complete attempt (almost every line is from the tutorial)



	//Create handle to FBO
	GLuint fbo;
	glGenFramebuffersEXT(1, &fbo);

	//bind FBO (what does this mean?)
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

	//create depth buffer for the FBO
	GLuint depthbuffer;
	glGenRenderbuffersEXT(1, &depthbuffer);

	//bind the renderbuffer
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);

	//specify size of the depth buffer
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);

	//attach the depth buffer to the frame buffer
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer);

	//attach a texture to the FBO
	//------------
	//create a texture
	GLuint img;
	glGenTextures(1, &img);
	glBindTexture(GL_TEXTURE_2D, img);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

	//attach the texture to the framebuffer
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0);

	//check that everything went ok
	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	
	if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		cout << gluErrorString(status) << endl;
	}

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
	glPushAttrib(GL_VIEWPORT_BIT);
	glViewport(0,0,width, height);


	// Render as normal here
	// output goes to the FBO and it’s attached buffers
	LookAt();
	DrawCube();
	ReadDepthBuffer();
	
	glPopAttrib();
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	//clean up
	glDeleteFramebuffersEXT(1, &fbo);
	glDeleteRenderbuffersEXT(1, &depthbuffer);


LookAt() is simply


void LookAt()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(70, 1, 1, 100);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	//gluLookAt(2, 2, 10, 2, 0, 0, 0, 1, 0);
	gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
	
}

And my read and write buffer are



void ReadDepthBuffer()
{
	
	float depths[width*height];
	glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
	WriteDepthBuffer("DepthBuffer.txt", depths);
}

void WriteDepthBuffer(const string &Filename, float* depths)
{
	ofstream fout(Filename.c_str());

	for(unsigned int im_x = 0; im_x < width; im_x++)
	{
		for(unsigned int im_y = 0; im_y < height; im_y++)
		{
			double CurrentDepth = depths[width*im_y + im_x];
			fout << im_x << " " << im_y << " " << CurrentDepth << endl;
		}
	}

	fout.close();

	cout << "Done Writing." << endl;
}

The output looks nothing like the depth buffer of the cube. Any thoughts?

Thanks,
Dave

Perhaps glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); will help?

add glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
befrore glreadpixels.
bcoz the default read buffer is the front buffer,
but now u are not rendering to the fron buffer but to ATTACHMENT0 of the fbo .

gd luck

Don’t think so…in the spec:
“For application-created framebuffer objects, the initial setting for ReadBuffer is COLOR_ATTACHMENT0_EXT.”

Anyway, you can always try binding a depth texture and reading from it…

And try making a window and use it for visual display of your buffers. Much better than .txt files!

I tried this


float depths[width*height];
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depths); //(x,y, width, height, format, type, *pixels)
WriteDepthFileVIL("buffer.jpg", depths);

but it’s still just junk. I took your advice though and wrote a jpg instead of a text file (which before I was interpreting in matlab).

I thought I had already bound a depth buffer with


	//create depth buffer for the FBO
	GLuint depthbuffer;
	glGenRenderbuffersEXT(1, &depthbuffer);

	//bind the renderbuffer
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);

	//specify size of the depth buffer
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);

	//attach the depth buffer to the frame buffer
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer);


So how would I read from that one?

Thanks,
Dave

Dave you really need to put some checking in your code…

In most examples, including I think the one I posted, they talk about checking if the FBO has been created properly. They can be a bit pernickety, so to save yourself a lot of time wrap the error checking around the creation stuff.

To be honest, I think reading it the way you did initially should work, but I haven’t got the hardware to test it right now…What I meant is use glFrameBufferTexture2D with a depth texture and a depth attachment(yes, works, that’s how shadowmaps work), and read the texel data(glGetTexImage) after rendering.

I did try that check they recommended, but it failed… but the error code was “no error”, so I thought it was ok? And now I called this after every line:


void CheckErrors()
{
	GLenum error = glGetError();
	cout << gluErrorString(error) << endl;
}

But everything said “no error”.

use this fbo class from gpgpu site
or @ least try to compare ur code to this class .to clean any mistake
http://sourceforge.net/project/showfiles.php?group_id=104004&package_id=158526&release_id=463385

The final job to do in setup is to check that the FBO is ‘complete’. Completeness refers to the state of the FBO being one which, given the current OpenGL state and its attachments, all is correct for you to render to it.

This test is done via a single function which returns the status of the currently bound FBO

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
If all has gone well then status will equal GL_FRAMEBUFFER_COMPLETE_EXT and your FBO is ready to be rendered to. Other error codes, as found in the spec, indicate other problems which might well have occurred when you tried to setup the FBO.

abdallah - thanks, i’ll check it out.

Scratt - I did try that function but it seemed to return “no error”.

Does the "no error’ value you get equate to GL_FRAMEBUFFER_COMPLETE_EXT though?