A framebuffer is a collection of attachments (renderbuffers and/or textures). It works just like rendering without a framebuffer. (in fact the browser is internally using a framebuffer to implement WebGL's canvas)
In your case you're missing a few things. You most likely need a depth buffer attached otherwise when you render your scene you won't get zBuffering and the wrong objects will appear in front.
// create renderbuffer
depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
// allocate renderbuffer
gl.renderbufferStorage(
gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
// attach renderebuffer
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER,
gl.DEPTH_ATTACHMENT,
gl.RENDERBUFFER,
depthBuffer);
In general you should also check your framebuffer works. After attaching all the attachments you call gl.checkFramebufferStatus
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
alert("this combination of attachments does not work");
return;
}
A framebuffer can be incomplete for any number of reasons. The most common is the attachments are not same size or the GPU doesn't support that combination of attachments. Note: In WebGL certain combinations are required to work but you since you might change the code later to use different formats it's probably still a good idea to check.
You also need to set the viewport by calling gl.viewport
whenever you switch framebuffers.
gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer);
gl.viewport(0, 0, someFramebufferWidth, someFramebufferHeight);
That includes putting it back when setting things back to the canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // render to canvas
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
Finally there's a bug in the code above in that you're only clearing the depth buffer of the framebuffer where you call gl.clear
. You want to call
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Since you're going to read the colors later otherwise old colors will be left over.
Finally, and I guess you know this. You figure out which pixel corresponds to the mouse click and call
var colorPicked = new Uint8Array(4);
gl.readPixels(pickX, pickY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, colorPicked);
Note that when you call gl.readPixels
you must have your framebuffer bound with gl.bindFramebuffer
or gl.readPixels
will read from the canvas.