In a WebGL 2 GLSL fragment shader, one can not access the pre-existing color value of the current pixel, i.e. the color that is already there in the framebuffer before the pixel that is currently calculated. I am woundering how one can get around this limitation?
For instance, let's say that I want to do some color post processing by running a fragment shader on a quad covering the whole screen. I'll use gamma correction as an example, but it could be any arbitrary function that takes a color for and return a new color. I would like to write code like this:
#version 300 es
precision highp float;
in vec2 uv;
out vec4 outColor;
void main() {
vec4 currentColor = readPixel(uv)
outColor = pow(currentColor, vec3(1.0, 1.0, 1.0) / 2.2);
}
However, there is no such function as readPixel
, so I do not know what color I am trying to gamma correct. I can think of a few approaches to tackle the problem:
- Leverage the blend modes. However, they are quite limited (all are linear, I think), and I don't think they will help me here.
- Include the post processing in all fragment shaders. If all fragment shaders that put pixels on the screen has the same post processing built in at the end, I don't need to do it in a separate pass. But this complicates my code, since every single fragment shader is suddenly dependant upon my post processing needs. It's not so much post any more.
- Use ping pong buffers. Render to one framebuffer, and read the pixels from a texture belonging to another framebuffer. The non-existing
readPixel
can then be replaced with the very much existingtexture
function. However, this can't be great for performance since I am basically copying the full frame each frame.
What is the best path forward here? Is there a fourth option that I am missing? Is there some established best practice in a situation like this?