c++ - OpenGL alpha 混合突然停止

标签 c++ opengl glsl

我使用 OpenGL 在每一帧上使用低 alpha(小于 0.1)将屏幕大小的四边形绘制到相同位置,中间没有 glClear(GL_COLOR_BUFFER_BIT)他们。通过这种方式,四边形应该越来越多地抑制先前帧的绘图的可见性。

然而,阻尼效果在几秒钟后停止。如果我为四边形使用不低于 0.1 的 alpha 值,它会按预期工作。在我看来,OpenGL 混合方程在多次迭代后失败(更高的 alpha 值需要更少的迭代来累积到 1,所以如果 alpha >= 0.1 问题不会发生)。 8bit 的 alpha 下限约为 0.0039,即 1/255,所以 alpha 0.01 应该没问题。

我尝试了几种混合设置,使用以下渲染方法:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_DEPTH_BUFFER_BIT);
// draw black quad with translucency (using glDrawArrays)

和简单的片段着色器:

#version 450

uniform vec4 Color;
out vec4 FragColor;

void main()
{
    FragColor = Color;
}

我该如何解决这个问题?

最佳答案

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.

你的推理在这里是错误的。如果你绘制一个 alpha 为 0.01 的黑色四边形和你描述的混合设置,你基本上每次迭代都会得到 new_color = 0.99 * old_color。作为迭代次数 i 的函数,它将是 new_color(i) = original_color * pow (0.99,i)。现在无限精度,这将向 0 移动。

但是正如您已经指出的那样,精度不是无限的。每一步都会重新量化。因此,如果您的 new_color 颜色值没有低于整数值的阈值,它将与以前保持不变。现在,如果我们将 x 视为 [0,255] 范围内的未归一化颜色值,并且我们假设量化只是通过通常的舍入规则完成的,我们必须得到至少 0.5 的差异才能得到不同的值:x - x * (1-alpha) > 0.5,或者只是 x > 0.5/alpha

所以在你的情况下,你得到 x > 50,这就是混合将“停止”的地方(并且低于它的所有内容将保持在开始时的状态,所以你会得到黑暗部分的“阴影”) .对于 0.1 的 alpha,它将在 x=5 处结束,这可能非常接近零,以至于您没有注意到它(使用您的特定显示和设置)。

编辑

让我推荐一个可行的策略。您必须避免迭代组合(至少对于非浮点帧缓冲区)。您想要实现淡入淡出的黑色效果。因此,您可以将原始内容渲染到纹理中,并一遍又一遍地渲染它,同时通过在帧与帧之间改变 alpha 值将其混合为黑色,因此您最终将 alpha 作为时间(或帧编号)的函数).使用线性过渡可能最有意义,但您甚至可以使用一些非线性函数来降低淡出的速度,就像您使用无限精度的原始方法所做的那样。

请注意,您根本不需要为此进行混合,您只需将纹理的颜色值与片段着色器中的某个统一“alpha”值相乘即可。

关于c++ - OpenGL alpha 混合突然停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25548179/

相关文章:

c++ - 修改 C++ unordered_map 中复杂类型的值

c++ - 将 IPv4/IPv6 地址和端口设置为 sockaddr_storage 结构

c++ - 问题延迟着色

c++ - 尝试将绘图分离到不同的视口(viewport)

OpenGL 3.0 帧缓冲区输出到附件而无需我指定?

javascript - 如何从 ArrayBuffer 在 WebGL 中渲染图像

C++11:将结构数组重新解释为结构成员数组

c++ - 为什么在变量中存储右值引用会导致它悬空

c++ - 索引是如何工作的?

performance - GLSL:标量与矢量性能