Using Render to Texture

Prepare the texture

You must create space on the GPU to store the actual image data. This is done by creating an empty texture. Note the NULL input data pointer.

glGenTextures(1, &renderTexture);
glBindTexture(GL_TEXTURE_2D, renderTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xSize, ySize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

Prepare the buffer

First, create a framebuffer:

glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

If we are rendering a 3D scene and wish to only show the closest objects, we must track the depth values for surfaces rendered. This means we need some storage for these values. This is done using a RenderBuffer object.

glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, xSize, ySize);

The depth storage needs to be attached to the current active framebuffer.

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer);

Similarly, storage for the color data is needed. We will be using the previously created texture for this:

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderTexture, 0);

Next, tell OpenGL where shaders can find the output buffer. Since multiple output buffers are allowed, this can be set as an array of values.

GLenum colorBuffer = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, &colorBuffer);

Once the buffer is prepared, you should check it for errors.

glCheckFramebufferStatus(GL_FRAMEBUFFER)

Render

You must set the output buffer to be used before issuing glDraw calls. The buffer will be used until it is set again.

//render to output 'frameBuffer' object
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
...

//render to default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
...

In shader

The GLSL vertex shader defines the int gl_VertexID input variable, which contains an ID number for each vertex. This should be the element ID when rendering with elements. This can be useful when using textures for storing raw data and not images.

The GLSL fragment shader defines the vec4 gl_FragCoord variable which contains the screen space coorindates of the current fragment. This can be useful for looking up a fragment's color in an input texture.

There can be multiple outputs from the fragment shader. Each output has an ID, similar to the slot IDs for uniform and attribute variables. This can be specified with the layout keyword. For example:

layout(location = 0) out vec4 fragColor;
layout(location = 1) out float fragDepth;