Reputation: 8530
I'm using OpenGL to draw a screen size quad to the same position with low alpha (lesser than 0.1
) on every frame, without glClear(GL_COLOR_BUFFER_BIT)
between them. This way the quad should increasingly damp the visibility of the drawings of the previous frames.
However the damping effect stops after some seconds. If I use alpha value no lower than 0.1
for the quad, it works as expected. It seems to me, that the OpenGL blending equation fails after a number of iterations (higher alpha values need less iteration to accumulate to 1
, so if alpha >= 0.1
the problem doesn't occur). The lower limit of alpha in 8bit is about 0.0039
, i.e. 1/255
, so alpha 0.01
should be fine.
I have tried several blending settings, using the following render method:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_DEPTH_BUFFER_BIT);
// draw black quad with translucency (using glDrawArrays)
And the simple fragment shader:
#version 450
uniform vec4 Color;
out vec4 FragColor;
void main()
{
FragColor = Color;
}
How could I fix this issue?
Upvotes: 1
Views: 746
Reputation: 45332
It seems to me, that the OpenGL blending equation fails after a number of iterations (higher alpha values need less iteration to accumulate to 1, so if alpha >=0.1 the problem doesn't occur). The lower limit of the alpha in 8bit is about 0.0039 (1/255), so alpha 0.01 should be fine.
Your reasoning is wrong here. If you draw a black quad with alpha of 0.01 and the blending setup you described, you basically get new_color = 0.99 * old_color
with every iteration. As a function of the iteration number i
, it would be new_color(i) = original_color * pow (0.99,i)
. Now with unlimited precision, this will move towards 0.
But as you already noted, the precision is not unlimited. You get a requantization with every step. So if your new_color
color value does not fall below the threshold for the integer value, it will stay the same as before. Now if we consider x
the unnomralized color value in the range [0,255], and we assume that the quantization is just done by usual rounding rules, we must get at a difference of at least 0.5 to get a different value: x - x * (1-alpha) > 0.5
, or simply x > 0.5 / alpha
.
So in your case, you get x > 50, and that is where the blending will "stop" (and everything below that will stay as it was at the beginning, so you get a "shadow" of the dark parts). For alpha of 0.1, it will end at x=5, which is probably close enough to zero that you didn't notice it (with your particular display and settings).
EDIT
Let me recommend a startegy that will work. You must avoid the iterative compontation (at least with non-floatingpoint framebuffers). You want to achieve a fade to black effect. So you could render your original content into a texture, and render that over and over again, while blending it to black by varying the alpha value from frame to frame, so you end up with alpha as a function of the time (or frame number). Using a linear transition would probably make the most sense, but you could even use some nonlinear function to get the slowdown of the fadeout as your original approach with unlimited precision would have done.
Note that you do not need blending at all for that, you simply can multiply the color value from the texture with some uniform "alpha" value in the fragment shader.
Upvotes: 4