Framebuffer Objects
WebGL doesn't let us just walk in and render to a texture. We must first set up a framebuffer object (FBO). When we first set up a WebGL context, a default framebuffer object is created automatically. This default framebuffer object has two attachments: the color framebuffer that is drawn to our screen and a depth buffer that is used to sort fragments. When we create our own framebuffer objects, we can give it other kinds of attachments, namely textures.
Rendering to textures is useful for many different applications. With them we can dynamically generate skyboxes. Or we generate alternative views of the scene that appear in mirrors or portals. We can use them to achieve motion blur or post-processing effects like edge detection. For now, however, we only care about shadows.
To perform shadow mapping, we need a map of the depths of the surfaces that the light "sees". We don't need the colors of these surfaces. Therefore, our framebuffer object needs a depth attachment but not a color attachment.
This JavaScript function creates a brand new framebuffer object whose depth attachment is a depth texture that we've made previously.
function initializeDepthFbo(depthTexture) {
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return framebuffer;
}
function initializeDepthFbo(depthTexture) { const framebuffer = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, null); return framebuffer; }
Now we've got the pieces in place to render to a texture.