重构复杂的 opengl 混合

Posted

技术标签:

【中文标题】重构复杂的 opengl 混合【英文标题】:Refactoring a complicated opengl blend 【发布时间】:2016-08-05 07:24:19 【问题描述】:

我正在尝试重现相当复杂的混合操作的效果(已更正)。

(1-(1-src_alpha)*dest_alpha)*src+(1-src_alpha)*dest_alpha*dest

srcdest 指的是源缓冲区和目标缓冲区中各自的 rgba 组件。我想要做的是使用glBlendFunc 和/或glBlendFuncSeparate 将其转换为一个混合链,可以调用它来产生与上述表达式相同的结果,可能是通过多次渲染相同的场景,每次渲染一次glBlend* 打电话。虽然很遗憾我无法将复杂的混合作为单个 glBlend* 调用进行,但在我看来,通过使用不同的 glBlend* 参数多次渲染我的场景,我仍然可以达到我想要的效果。我在想我可能需要 3 次这样的调用,但也可以分两次进行。

编辑:

要了解混合函数的作用,请首先考虑常规 alpha 混合 src * src_alpha + dest * (1 - src_alpha)。这种混合风格适用于几乎所有源不包含预乘 Alpha 的 Alpha 混合,特别是当我们渲染到最终设备(例如屏幕或其他设备)时,目标明确为或可能假定为不透明。

如果目的地已经是不透明的,那么这个复杂的混合函数将产生与前面提到的普通混合函数相同的结果,同时将目的地保持为不透明,而如果目的地恰好是完全透明的,那么复杂的混合函数会降级为源副本并继承源的透明度。因此,复杂混合函数实际上所做的只是根据目标 alpha 在这两个极端值之间进行线性插值。

编辑:需要更正上面的混合函数...我错误地考虑了它。我在下面显示推导以进行验证:

首先,我从一个基本的混合函数开始:

src * src_alpha + dest * (1 - src_alpha)

而我想要做的是混合 that 与 src,取决于 dest_alpha,所以上面的函数乘以 dest_alpha,我将它加到源乘以 1 - dest_alpha,如下:

src * (1-dest_alpha) + (src * src_alpha + dest * (1 - src_alpha)) * dest_alpha

算术重构给了我这个:

(1-(1-src_alpha)*dest_alpha)*src+(1-src_alpha)*dest_alpha*dest

【问题讨论】:

一旦完成,你希望你的目标 alpha 变成什么? 你不能使用着色器为你做这个计算,然后使用一些搅拌器功能来渲染一个四边形吗?我根本不熟悉混合,所以只是想知道。 @Jas:混合是着色器无法做到的事情之一(在绘制时在每个三角形的基础上)——它是 GPU 中的硬连线电路。当然 OP 实际上可能是从几层合成一张图片,在这种情况下,这不再是混合,而是合成。 是的,这正是我正在做的......从许多不同的层构建图片。 【参考方案1】:

我想通了,所以如果其他人有任何需要,这是我发现的:

首先,我打电话给

glblendfuncseparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)

然后我正常绘制场景。假设源具有非预乘 alpha 并且正在与不透明背景混合,这将在颜色通道上产生正确的混合样式。虽然保留了destination的原始alpha,但可以在下一步使用:

glblendfuncseparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

然后我重新绘制与之前完全相同的场景。这进一步线性插值原始源和基于目标 alpha 的上述混合结果之间的颜色通道,并以结果始终大于或等于源 alpha 或目标 alpha 的方式组合 alpha 分量,但是仍然总是限制在 0 和 1 之间,就像源 alpha 值和目标 alpha 值一样。

【讨论】:

以上是关于重构复杂的 opengl 混合的主要内容,如果未能解决你的问题,请参考以下文章

✠OpenGL-14-其他技术

◮OpenGL-混合

混合 OpenGL 和 UIKit

IOS OpenGL ES GPUImage 图像透明混合 GPUImageAlphaBlendFilter

IOS OpenGL ES GPUImage 图像源混合 GPUImageSourceOverBlendFilter

使用 OpenGL 混合音频