【问题标题】:Smoothly invertible additive/subtractive luminance blending in OpenGLOpenGL中平滑可逆的加法/减法亮度混合
【发布时间】:2014-06-04 06:18:04
【问题描述】:

我正在尝试执行一项相当具体的混合操作,但看起来应该相对简单。我在 alpha 值为 1 的背景上显示亮度纹理。

例如,这可能是另一个图像顶部的简单棋盘:

我希望纹理根据以下条件线性增加/减少背景的亮度:

(R_b + R_t * w, G_b + G_t * w, B_b + B_t * w, 1.0)

其中*_b 是背景像素值(介于 0 和 1 之间),*_t 是叠加纹理的有符号像素值(介于 -1 和 1 之间),w 是一个加权参数,它也可以变化介于 -1 和 1 之间。目标是通过改变 w 的符号和幅度,我可以通过棋盘纹理平滑地改变背景调制的幅度和极性。

给你一个图形示例:

使用glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) 并仅改变叠加层的 alpha 值并不能完全达到我想要的效果,因为我不能使用负 alpha 值来反转叠加层的极性。

有没有办法使用固定管道进行这种类型的线性加法/减法混合,或者如果失败了,是否可以使用着色器来实现?

更新

为了进一步说明,我添加了一个粗略的 PyOpenGL 示例,说明我正在尝试做什么here

更新 2

完全清楚,如果w > 0,我想增加我棋盘上白色方块内每个像素的亮度,并减少 黑色方块内每个像素的亮度。如果w < 0 我想做相反的事情。

derhass 的答案非常接近我正在寻找的内容,但只影响白色方块中的像素,而不影响黑色方块中的像素:

人类在判断绝对亮度方面很糟糕,但如果我将叠加层的颜色设置为红色 (glColor4f(1., 0., 0., 0.25)),差异会更明显:

如您所见,这会导致从白色方块中添加/减去红色,但不会更改黑色方块。

【问题讨论】:

  • 您的目标是哪个版本的 GL?不再支持亮度纹理(3.1+ 不兼容)。您可以(相当粗暴地)使用深度纹理来获得单分量纹理,其中 r,g,b 具有相同的值并且 a 是常量 1.0 或使用GL_REDgb 将是未定义的,a 将是 1.0)。
  • 既然你说想要签名颜色,我会排除深度纹理。您可能需要 GL_R8_SNORM 和一些 swizzling(无论是扩展还是在实际着色器中)。
  • @AndonM.Coleman 为了给你一些背景信息,这段代码是用 PyOpenGL 编写的相当深奥的科学软件的一部分,它已经充满了遗留的 OGL API 调用,所以我并不特别担心GL_LUMINANCE 现在已弃用。我并不特别需要有符号的颜色 - 我所追求的是一种单一的混合模式,它允许我以加法和减法方式调制背景图像的亮度。
  • 这正是引入可编程管道的时候。
  • @BartekBanachewicz 我绝对愿意为此使用着色器,但我的印象是这是不可能的,因为混合是对片段着色器的输出进行的。

标签: opengl alphablending blending pyopengl


【解决方案1】:

我认为您可以使用 GL 的混合,只要您的 w 参数不会因像素而异,而对于覆盖纹理的整个绘制调用来说是全局的(正如您的图像所暗示的那样)。您只需要根据w 的符号设置混合方程即可:

将混合因子设置为glBlendFunc(GL_SRC_ALPHA,GL_ONE),并且

  • 对于 w>=0:使用 glBlendEquation(GL_FUNC_ADD) 并将 alpha 设置为 w

  • 对于 wglBlendEquation(GL_FUNC_REVERSE_SUBTRACT) 并将 alpha 设置为 -w

如前所述,这也会修改输出的 alpha 分量,但您希望它为 1.0。正如你所说,当你渲染背景时,你的帧缓冲已经 alpha=1。所以你可以只使用glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE,GL_ZERO,GL_ONE),它与上面的等式结合起来会将结果的alpha设置为目的地的alpha,A_b在你的符号中。

更新

事实证明,问题中的公式不是所需的行为,并且每次绘图调用只需要GL_FUNC_ADD GL_FUNC_REVERSE_SUBTRACT 的假设不成立。

但是,如果使用 浮点 颜色缓冲区,则可以使用负 alpha 值 (ARB_color_buffer_float)。

如果颜色缓冲区是定点的,则源的分量和 目标值和混合因子均被限制为 [0; 1] 或 [-1; 1]分别用于无符号归一化或有符号归一化 在评估混合方程之前的颜色缓冲区。如果颜色 缓冲区是浮点数,不会发生钳位。结果四 值被发送到下一个操作。

请注意,此扩展引入了glClampColor() 函数并定义了目标GL_CLAMP_READ_COLORGL_CLAMP_VERTEX_COLORGL_CLAMP_FRAGMENT_COLOR。后两者在现代 GL 中已弃用,仅与已弃用的固定功能管道相关。

【讨论】:

  • 看起来几乎是正确的,但它并不能完全解决我的问题。使用glBlendEquation(GL_FUNC_ADD),棋盘中“明亮”方块下方区域的亮度会增加(这很好),但“暗”方块不会减少。同样,使用glBlendEquation(GL_FUNC_REVERSE_SUBTRACT) 时,“亮”方块会减少(这也很好),但“暗”方块仍然没有被修改。够清楚吗?我会尝试为我的问题添加更多解释。
  • @ali_m:嗯,它完全模拟了你给出的公式。而且公式似乎不仅仅是您想要的:在黑色方块中,您的 X_t 值都为零,根据您的公式,这将导致目标值保持原样。 也许你只是想要glBendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA),但这并不清楚。
  • 对不起,你是对的——这完全是我的错!我曾设想使用 1 到 -1 之间的 GL_RGB_SNORM 纹理符号值,这将允许我同时增加和减少像素值(我认为 Andon 的评论暗示了这一点)。
  • @ali_m:好的,所以在这种情况下,您可能仍然可以将混合与浮点帧缓冲区结合使用(参见GL_ARB_color_buffer_float spec 的第 4.1.8 节(混合)),基本上允许您使用负 alpha 值。不过,您可能需要另一个渲染通道来将结果转换为可以显示的标准 UNORM 数据。
  • 很好 - 这似乎可以解决问题!在我的真实代码中,我已经渲染到帧缓冲区,因此只需将帧缓冲区颜色附件更改为浮点格式,并使用 glClampColor() 函数关闭钳位。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多