Quick example, render_to_texture (2D)

Let's assume we want to render to a texture and we also want depth testing to take place. We need to create a color texture and we need to attach it to the FBO. We need a depth buffer RenderBuffer and attach it to the FBO. Once you are done rendering to this texture, you can use it like any other texture. In this case, we don't care what happens to the depth values. If you want to access the depth (for example, from within your shader), you need to make a depth texture instead of a depth buffer RenderBuffer. Please look at the other examples. Also, keep in mind we are using the GL_RGBA8 format here which is a format supported by all GPUs.

//RGBA8 2D texture, 24 bit depth texture, 256x256glGenTextures(1,&color_tex);glBindTexture(GL_TEXTURE_2D,color_tex);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);//NULL means reserve texture memory, but texels are undefinedglTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);//-------------------------glGenFramebuffersEXT(1,&fb);glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);//Attach 2D texture to this FBOglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,color_tex,0);//-------------------------glGenRenderbuffersEXT(1,&depth_rb);glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depth_rb);glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,256,256);//-------------------------//Attach depth buffer to FBOglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,depth_rb);//-------------------------//Does the GPU support current FBO configuration?GLenumstatus;status=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);switch(status){caseGL_FRAMEBUFFER_COMPLETE_EXT:cout<<"good";default:HANDLE_THE_ERROR;}//-------------------------//and now you can render to GL_TEXTURE_2DglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);glClearColor(0.0,0.0,0.0,0.0);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//-------------------------glViewport(0,0,256,256);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(0.0,256.0,0.0,256.0,-1.0,1.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();//-------------------------glDisable(GL_TEXTURE_2D);glDisable(GL_BLEND);glEnable(GL_DEPTH_TEST);//-------------------------//**************************//RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0}//Read http://www.opengl.org/wiki/VBO_-_just_examplesRenderATriangle();//-------------------------GLubytepixels[4*4*4];glReadPixels(0,0,4,4,GL_BGRA,GL_UNSIGNED_BYTE,pixels);//pixels 0, 1, 2 should be white//pixel 4 should be black//----------------//Bind 0, which means render to back bufferglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);

And in the end, cleanup

//Delete resourcesglDeleteTextures(1,&color_tex);glDeleteRenderbuffersEXT(1,&depth_rb);//Bind 0, which means render to back buffer, as a result, fb is unboundglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);glDeleteFramebuffersEXT(1,&fb);

Quick example, render_to_texture (2D), mipmaps

This example is nearly identical to the above sample code with one difference : glGenerateMipmapEXT is used to generate the mipmaps. You can use it to generate mipmaps whenever you want. Generally, you render to the texture, then unbind the FBO with glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0), then bind the texture with glBindTexture, then call glGenerateMipmapEXT. ALSO, notice that glGenerateMipmapEXT doesn't have an "s".

//RGBA8 2D texture, 24 bit depth texture, 256x256glGenTextures(1,&color_tex);glBindTexture(GL_TEXTURE_2D,color_tex);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//NULL means reserve texture memory, but texels are undefined//**** Tell OpenGL to reserve level 0glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);//You must reserve memory for other mipmaps levels as well either by making a series of calls to//glTexImage2D or use glGenerateMipmapEXT(GL_TEXTURE_2D).//Here, we'll use :glGenerateMipmapEXT(GL_TEXTURE_2D)//-------------------------glGenFramebuffersEXT(1,&fb);glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);//Attach 2D texture to this FBOglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,color_tex,0);//-------------------------glGenRenderbuffersEXT(1,&depth_rb);glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depth_rb);glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,256,256);//-------------------------//Attach depth buffer to FBOglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,depth_rb);//-------------------------//Does the GPU support current FBO configuration?GLenumstatus;status=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);switch(status){caseGL_FRAMEBUFFER_COMPLETE_EXT:cout<<"good";default:HANDLE_THE_ERROR;}//-------------------------//and now you can render to GL_TEXTURE_2DglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);glClearColor(0.0,0.0,0.0,0.0);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//-------------------------glViewport(0,0,256,256);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(0.0,256.0,0.0,256.0,-1.0,1.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();//-------------------------glDisable(GL_TEXTURE_2D);glDisable(GL_BLEND);glEnable(GL_DEPTH_TEST);//-------------------------//**************************//RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0}//Read http://www.opengl.org/wiki/VBO_-_just_examplesRenderATriangle();//-------------------------GLubytepixels[4*4*4];glReadPixels(0,0,4,4,GL_BGRA,GL_UNSIGNED_BYTE,pixels);//pixels 0, 1, 2 should be white//pixel 4 should be black//----------------//Bind 0, which means render to back bufferglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);//----------------//**** Now that we rendered to level 0 of the texture, we must generate the mipmaps.//This should be quick since it is done on the GPU.glBindTexture(GL_TEXTURE_2D,color_tex);glGenerateMipmapEXT(GL_TEXTURE_2D)

And in the end, cleanup

//Delete resourcesglDeleteTextures(1,&color_tex);glDeleteRenderbuffersEXT(1,&depth_rb);//Bind 0, which means render to back buffer, as a result, fb is unboundglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);glDeleteFramebuffersEXT(1,&fb);

Quick example, render_to_texture (Cubemap)

In case you want to have dynamic reflections on a shiny object, you would want to do render to a cubemap.

The concept behind rendering to a cubemap is the following. Bind a cubemap face, then render to it. Bind another cubemap face, then render to it. There are 6 faces in total. You may think that rendering 6 times your scene will drag down performance and you are right. Don't update the cubemap often. You can update every 2 frames. Make your cubemap small, for example 256x256.

//RGBA8 Cubemap texture, 24 bit depth texture, 256x256glGenTextures(1,&color_tex);glBindTexture(GL_TEXTURE_CUBE_MAP,color_tex);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_NEAREST);//NULL means reserve texture memory, but texels are undefinedglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+0,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+1,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+2,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+3,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+4,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+5,0,GL_RGBA8,256,256,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);//-------------------------glGenFramebuffersEXT(1,&fb);glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);//Attach one of the faces of the Cubemap texture to this FBOglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_CUBE_MAP_POSITIVE_X,color_tex,0);//-------------------------glGenRenderbuffersEXT(1,&depth_rb);glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depth_rb);glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,256,256);//-------------------------//Attach depth buffer to FBOglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,depth_rb);//-------------------------//Does the GPU support current FBO configuration?GLenumstatus;status=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);switch(status){caseGL_FRAMEBUFFER_COMPLETE_EXT:cout<<"good";default:HANDLE_THE_ERROR;}//-------------------------//and now you can render to GL_TEXTURE_CUBE_MAP_POSITIVE_X//In order to render to the other faces, do this :glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_CUBE_MAP_POSITIVE_Y,color_tex,0);//... now renderglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_CUBE_MAP_POSITIVE_Z,color_tex,0);//... now render//... and so on

And in the end, cleanup

//Delete resourcesglDeleteTextures(1,&color_tex);glDeleteRenderbuffersEXT(1,&depth_rb);//Bind 0, which means render to back buffer, as a result, fb is unboundglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);glDeleteFramebuffersEXT(1,&fb);

Quick example, render_to_texture (2D Depth texture ONLY)

In this example, notice glDrawBuffer(GL_NONE) and glReadBuffer(GL_NONE). We don't need a color output so that is why we set them to GL_NONE. The important call is glDrawBuffer(GL_NONE). We do not want to render to a color buffer.

Quick example, render_to_buffer (p-buffer replacement)

Around 2000, the p-buffer extension was released which was used to do offscreen rendering. These days, it is best to use GL_EXT_framebuffer_object. This extension is much easier to use compared to p-buffer and best of all, it is cross platform. This example creates a RenderBuffer using 2 calls to glRenderbufferStorageEXT. The first call is for creating a color buffer and the second is used to create a depth buffer.

Limitations of GL_EXT_framebuffer_object

One of the limitations of GL_EXT_framebuffer_object is that when you bind a color buffer and then you bind a depth buffer, both must have the same
width and height or else the state of the FBO is considered invalid (incomplete).
This means if you have 1 FBO that is 64x64, another which is 512x64, another that is 1024x1024, for each of those you have to allocate a separate depth buffer (if you need depth testing of course). This obviously wastes memory.
In GL 3.0, FBO became core and that limitation was removed.
You can create 1 depth buffer that is 1024x1024 and bind them to all 3 FBOs. Notice that the depth buffer is large enough for even the smaller textures like 64x64.

1 FBO or more

Is it better to make 1 FBO and bind your texture to it each time you need to render to the texture?
An FBO itself doesn't use much memory. It is a state vector object. In terms of performance, each time you bind, the driver needs to validate the state which costs CPU time. Logically, it would be better to have 1 FBO per Render_To_Texture (RTT).
However, it has been found that you get a speed boost if your textures is the same size and you use 1 FBO for them.
If you have 10 textures that are 64x64 and 10 textures that are 512x64, make 2 FBOs. One FBO for each group.

The main framebuffer

Can you bind the main framebuffer's depth buffer as a depth buffer for your FBO? No. You must create a depth texture or a depth Render Buffer.

Does GL 3.0 allow using the main depth buffer? No.

Can you do MRT (multiple render targets) and have the main color framebuffer as one of the targets? No, you can only target a texture or a Render Buffer. GL 3.0 doesn't support it either.

MSAA

Are multisample Render_To_Texture (RTT) supported?
Not directly. You need GL_EXT_framebuffer_multisample and you would have to copy the contents of the AA-FBO to a standard RTT.
Note that GL_EXT_framebuffer_multisample also became core in GL 3.0
See also http://www.opengl.org/wiki/GL_EXT_framebuffer_multisample

Depth only

This is similar to the case above (Color texture, Depth texture) except that since there is no color buffer, call glDrawBuffer(GL_NONE) before or after calling glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb) and then render. When you are done, call glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) to render to the main framebuffer. This is important, call glDrawBuffer(GL_BACK) after. If you call before glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0), a GL error will be raised.

As for your fragment shader, you should write to gl_FragColor or whatever your color output it. The GPU will automatically generate the depth value and write to gl_FragDepth. The color value is obviously dropped automatically by the GPU. Example

Color only

Simply disable depth testing (glDisable(GL_DEPTH_TEST) and set the depth mask to FALSE (glDepthMask(GL_FALSE)) before you render to your RTT.

Stencil

NEVER EVER MAKE A STENCIL buffer. All GPUs and all drivers do not support an independent stencil buffer. If you need a stencil buffer, then you need to make a Depth=24, Stencil=8 buffer, also called D24S8. Please search for the example about GL_EXT_packed_depth_stencil on this page.

MRT

Talk about MRT

MRT and cubemaps

Talk about MRT and cubemaps

glReadPixels

Yes, you can bind a FBO and then render to it and then read with with a call to glReadPixels. It doesn't matter if what you have attached to the FBO is a RenderBuffer or a texture, glReadPixels will still read it and it will return the results.

For RTT (Render To Texture), if you will be using glGetTexImage, it is recommended that you unbind the FBO, make the texture current with a call to glActiveTexture and glBindTexture and use glGetTexImage. It is recommended that you avoid glGetTexImage and use the glReadPixels method since certain drivers don't do anything when you call glGetTexImage.