ChatGPT insists that when using a framebuffer and attaching multiple draw buffers, the 0-indexed one will be the one that when you write to in the shader, it will be rendered on the canvas. However I don't find it to be the case.
Here's how I setup:
// Create and bind framebuffer
multiFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, multiFrameBuffer);
// Create textures for color attachments
const textureRender = createTexture(gl);
const textureSmoothed = createTexture(gl);
const textureWithChangeMarks = createTexture(gl);
// Attach textures to framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureRender, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, textureSmoothed, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, textureWithChangeMarks, 0);
// Specify draw buffers
gl.drawBuffers([
gl.COLOR_ATTACHMENT0,
gl.COLOR_ATTACHMENT1,
gl.COLOR_ATTACHMENT2
]);
in my fragment shader I define:
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 mergedColor;
layout(location = 2) out vec4 changedColor;
I write colors to all vectors, I expect that writing to fragColor will be the rendered pixels on the canvas associated with the webgl context, but nothing renders.
If I readPixels from the other two - I get the buffer as expected.
I haven't tried to read like that from attachment0 - but I'd like to be able to directly render to the canvas.
You can only do either, render to a framebuffer or render to the canvas (the default framebuffer). Afaik the default framebuffer (bound when calling
gl.bindFramebuffer(gl.FRAMEBUFFER, null)) can not be configured outside the arguments given during context creation, meaning it'll always have one and only one color attachment.If you're using webgl2 you can use
blitFramebufferto copy the contents from yourREAD_FRAMEBUFFERto yourDRAW_FRAMEBUFFER, using theCOLOR_BUFFER_BITthis will copy the contents of your first color attachment to the canvas. In WebGL1 you'd need to draw a screenspace rectangle and manually blit the texture using a simple fragment shader.