Framebuffer Example

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: