Framebuffer Example

Render into a framebuffer and use it as a texture.

The Framebuffer Example shows how to render into a framebuffer, create a texture of it, and apply the texture to an object in normal on-screen rendering.

The example has a moving and rotating cube, which has another textured cube drawn into it via the framebuffer object. The cube in the framebuffer can be rotated using Sliders from Qt Quick Controls.

Preparing the Framebuffer

We first define the variables we need for the render-to-texture framebuffer:

 var rttFramebuffer;
 var rttTexture;
 var rttWidth = 512;
 var rttHeight = 512;

Then, in the initializeGL function, we create the framebuffer object:

 // Create the framebuffer object
 rttFramebuffer = gl.createFramebuffer();
 rttFramebuffer.name = "OffscreenRenderTarget";
 gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);

Creating the Texture

After the creation of the framebuffer, we create the texture:

 // Create the texture
 rttTexture = gl.createTexture();
 rttTexture.name = "OffscreenRenderTargetTexture";
 gl.bindTexture(gl.TEXTURE_2D, rttTexture);
 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
 gl.texImage2D(gl.TEXTURE_2D, 0,
               gl.RGBA, rttWidth, rttHeight,
               0, gl.RGBA, gl.UNSIGNED_BYTE,
               null);
 gl.generateMipmap(gl.TEXTURE_2D);

Then we need to bind the texture as a color attachment, create and bind a render buffer, and bind the depth attachment:

 // Bind the texture as color attachment, create and bind a depth buffer
 gl.framebufferTexture2D(gl.FRAMEBUFFER,
                         gl.COLOR_ATTACHMENT0,
                         gl.TEXTURE_2D, rttTexture, 0);
 var renderbuffer = gl.createRenderbuffer();
 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
 gl.renderbufferStorage(gl.RENDERBUFFER,
                        gl.DEPTH_COMPONENT16,
                        rttWidth, rttHeight);
 gl.framebufferRenderbuffer(gl.FRAMEBUFFER,
                            gl.DEPTH_ATTACHMENT,
                            gl.RENDERBUFFER, renderbuffer);

Rendering into the Framebuffer

In paintGL function, we first need to draw the scene into the framebuffer. We start by binding the framebuffer object and setting a viewport:

 // bind the FBO and setup viewport
 gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
 gl.viewport(0, 0, rttWidth, rttHeight);

Then, we need to bind the loaded texture we want to use in rendering into the framebuffer object:

 // Bind the loaded texture
 gl.bindTexture(gl.TEXTURE_2D, cubeTexture);

And then we can draw the textured cube into the framebuffer:

 // Draw the cube to the FBO
 gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

Using the Framebuffer as a Texture

First, we bind the render-to-texture right after drawing, and generate mipmaps:

 // Bind the render-to-texture and generate mipmaps
 gl.bindTexture(gl.TEXTURE_2D, rttTexture);
 gl.generateMipmap(gl.TEXTURE_2D);

Then we need to bind the default framebuffer (screen), and set up the viewport:

 // Bind default framebuffer and setup viewport accordingly
 gl.bindFramebuffer(gl.FRAMEBUFFER, 0);
 gl.viewport(0, 0,
             canvas.width * canvas.devicePixelRatio,
             canvas.height * canvas.devicePixelRatio);

And finally, we draw the on-screen view:

 // Draw the on-screen cube
 gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

Files:

Images: