-
A framebuffer object (FBO) allows WebGL programmer to render images to other memory
location other than the default framebuffer.
-
Remember the jargons from the first lecture:
- Buffer = "a region of physical memory used to temporarily store data "
(according Wikipedia).
- In our context, a buffer mostly resides in the GPU.
- Framebuffer = a buffer that holds the image that is displyaed on the monitor.
-
With an FBO, you can ask WebGL to render to receivers other than the monitor:
- Textures: We are already familiar with this.
-
Render buffers: Same as textures but support fewer operations.
- You cannot use WebGL commands to read anything from a render buffer.
- You cannot access a render buffer in a shader.
- They only serve as targets for rendered images and must be use with an FBO.
- However, they are less of a hassle to maintain than a texture.
-
An FBO allows for post-processing of rendered images.
- Render a 3D scene to a texture.
- Operate on the rendered image with another shader.
-
To create an FBO, use the
gl.createFramebufferObject()
command.
You only need one FBO most of the time, so this command is only called once in an application.
var fbo = gl.createFramebuffer();
-
Here's how to render to a texture rather than the monitor:
// Step 1: Bind the FBO.
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
// Step 2: Attach the texture to the FBO.
gl.framebufferTexture2D(
// First argument is always gl.FRAMEBUFFER
gl.FRAMEBUFFER,
// The second argument indicates the "attachment slot" of the FBO.
// Basically, it indicates the function of the texture that you are attaching.
// gl.COLOR_ATTACHMENT0 means that the texture will serve as the zeroth color buffer.
// By default, this is the only color buffer attachment slot of that you can use in vanially WebGL.
// To use other color buffer attachment slot, you need an extension. (We will cover this later.)
gl.COLOR_ATTACHMENT0,
// The third argument indicates the kind of texture we are attaching.
// Since we are attaching a TEXTURE_2D, we give it gl.TEXTURE_2D
gl.TEXTURE_2D,
// The fourth argument is the texture that you want to attach.
// Of course, this must be created before hand.
renderTexture,
// The fifth argument is the mipmap level of the texture.
// This is always 0.
0
);
// Step 3: Do your rendering as usual.
{
gl.clearColor(0.75, 0.75, 0.75, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//
// Code omitted for brevity.
//
// Step 4: Flush the buffer just to be sure everything is rendered to the texture.
gl.flush();
}
// Step 4: Detach the texture.
// Use the same arguments as the command in Step 2, but now the texture is null.
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
null, // null texture means we are detaching.
0);
// Step 5: Unbind the FBO.
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-
In Lecture 7, we learned how to create a texture from an image.
However, the renderTexture
we used above is not created from an image.
It is originally a blank texture.
To create a blank texture is a slightly different from creating a texture from an image.
Everything is the same except for the use of the texImage2D
command.
function createFloatTexture(gl, width, height) {
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
// Always gl.TEXTURE_2D for a 2D texture.
gl.TEXTURE_2D,
// Mipmap level. Always 0.
0,
// Internal format of each pixel. Here we want an RGBA texture.
gl.RGBA,
// Width of the texture.
width,
// Height of the texture.
height,
// Width of the border of the texture. Always 0.
0,
// The pixel format of the data that is going to be uploaded to the GPU.
// We have no data here, so use something that matches the internal format.
gl.RGBA,
// The type of each component of the pixel that is going to be uploaded.
// Here we want a floating point texture.
gl.FLOAT,
// The data that is going to be uploaded.
// We don't have any data, so we give null.
// WebGL will just allocate the texture and leave it blank.
null
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
var renderTexture = createFloatTexture(gl, 512, 512);
-
With the command above, we create a texture whose pixel components are stored as floating point
numbers.
This is not a feature supported by vanilla WebGL.
We need WebGL extensions to use it, and here is how to enable the extensions:
var gl = initializeWebGL($("#webglCanvas"));
gl.getExtension("OES_texture_float");
gl.getExtension("OES_texture_float_linear");
There are two extensions that we enabled.
OES_texture_float
allows floating point textures.
-
OES_texture_float_linear
allows gl.LINEAR
to be specified
as TEXTURE_MAG_FILTER
and TEXTURE_MIN_FILTER
parameters
of floating point textures.