// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,renderedTexture,0);// Set the list of draw buffers.
GLenumDrawBuffers[1]={GL_COLOR_ATTACHMENT0};glDrawBuffers(1,DrawBuffers);// "1" is the size of DrawBuffers

Something may have gone wrong during the process, depending on the capabilities of the GPU. This is how you check it :

Rendering to the texture

// Render to our framebuffer
glBindFramebuffer(GL_FRAMEBUFFER,FramebufferName);glViewport(0,0,1024,768);// Render on the whole framebuffer, complete from the lower left corner to the upper right

The fragment shader just needs a minor adaptation :

layout(location=0)outvec3color;

This means that when writing in the variable “color”, we will actually write in the Render Target 0, which happens to be our texure because DrawBuffers[0] is GL_COLOR_ATTACHMENTi, which is, in our case, renderedTexture.

To recap :

color will be written to the first buffer because of layout(location=0).

The first buffer is GL_COLOR_ATTACHMENT0 because of DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}

GL_COLOR_ATTACHMENT0 has renderedTexture attached, so this is where your color is written.

In other words, you can replace GL_COLOR_ATTACHMENT0 by GL_COLOR_ATTACHMENT2 and it will still work.

Note : there is no layout(location=i) in OpenGL < 3.3, but you use glFragData[i] = mvvalue anyway.

Using the rendered texture

We’re going to draw a simple quad that fills the screen. We need the usual buffers, shaders, IDs, …

// The fullscreen quad's FBO
GLuintquad_VertexArrayID;glGenVertexArrays(1,&quad_VertexArrayID);glBindVertexArray(quad_VertexArrayID);staticconstGLfloatg_quad_vertex_buffer_data[]={-1.0f,-1.0f,0.0f,1.0f,-1.0f,0.0f,-1.0f,1.0f,0.0f,-1.0f,1.0f,0.0f,1.0f,-1.0f,0.0f,1.0f,1.0f,0.0f,};GLuintquad_vertexbuffer;glGenBuffers(1,&quad_vertexbuffer);glBindBuffer(GL_ARRAY_BUFFER,quad_vertexbuffer);glBufferData(GL_ARRAY_BUFFER,sizeof(g_quad_vertex_buffer_data),g_quad_vertex_buffer_data,GL_STATIC_DRAW);// Create and compile our GLSL program from the shaders
GLuintquad_programID=LoadShaders("Passthrough.vertexshader","SimpleTexture.fragmentshader");GLuinttexID=glGetUniformLocation(quad_programID,"renderedTexture");GLuinttimeID=glGetUniformLocation(quad_programID,"time");

Now you want to render to the screen. This is done by using 0 as the second parameter of glBindFramebuffer.

// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER,0);glViewport(0,0,1024,768);// Render on the whole framebuffer, complete from the lower left corner to the upper right

(“24” is the precision, in bits. You can choose between 16, 24 and 32, depending on your needs. Usually 24 is fine)

This should be enough to get you started, but the provided source code implements this too.

Note that this should be somewhat slower, because the driver won’t be able to use some optimisations such as Hi-Z.

In this screenshot, the depth levels are artificially “prettified”. Usually, its much more difficult to see anything on a depth texture. Near = Z near 0 = black, far = Z near 1 = white.

Multisampling

You can write to multisampled textures instead of “basic” textures : you just have to replace glTexImage2D by glTexImage2DMultisample in the C++ code, and sampler2D/texture by sampler2DMS/texelFetch in the fragment shader.

There is a big caveat, though : texelFetch needs another argument, which is the number of the sample to fetch. In other words, there is no automatic “filtering” (the correct term, when talking about multisampling, is “resolution”).

So you may have to resolve the MS texture yourself, in another, non-MS texture, thanks to yet another shader.

Nothing difficult, but it’s just bulky.

Multiple Render Targets

You may write to several textures at the same time.

Simply create several textures (all with the correct and same size !), call glFramebufferTexture with a different color attachement for each, call glDrawBuffers with updated parameters ( something like (2,{GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1}})), and add another output variable in your fragment shader :

layout(location=1)outvec3normal_tangentspace;// or whatever

Hint : If you effectively need to output a vector in a texture, floating-point textures exist, with 16 or 32 bit precision instead of 8… See glTexImage2D’s reference (search for GL_FLOAT).