重构复杂的 opengl 混合
Refactoring a complicated opengl blend
我正在尝试重现相当复杂的混合操作的效果(已更正)。
(1-(1-src_alpha)*dest_alpha)*src+(1-src_alpha)*dest_alpha*dest
src
和 dest
指的是源缓冲区和目标缓冲区中的相应 rgba 组件。我想做的是使用 glBlendFunc
and/or 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
我弄明白了,所以如果其他人有任何需要,这是我发现的:
首先,我打电话给
glblendfuncseparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)
然后我正常画场景。假设源具有非预乘 alpha 并且正在与不透明背景混合,这将在颜色通道上产生正确的混合样式。虽然保留了desination的原始alpha,但可以在下一步使用:
glblendfuncseparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
然后我重新绘制了与之前完全相同的场景。这进一步在原始源和基于目标 alpha 的上述混合结果之间线性插值颜色通道,并以结果始终大于或等于源或目标 alpha 的方式组合 alpha 分量,但是仍然始终限制在 0 和 1 之间,就像源和目标 alpha 值一样。
我正在尝试重现相当复杂的混合操作的效果(已更正)。
(1-(1-src_alpha)*dest_alpha)*src+(1-src_alpha)*dest_alpha*dest
src
和 dest
指的是源缓冲区和目标缓冲区中的相应 rgba 组件。我想做的是使用 glBlendFunc
and/or 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
我弄明白了,所以如果其他人有任何需要,这是我发现的:
首先,我打电话给
glblendfuncseparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)
然后我正常画场景。假设源具有非预乘 alpha 并且正在与不透明背景混合,这将在颜色通道上产生正确的混合样式。虽然保留了desination的原始alpha,但可以在下一步使用:
glblendfuncseparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
然后我重新绘制了与之前完全相同的场景。这进一步在原始源和基于目标 alpha 的上述混合结果之间线性插值颜色通道,并以结果始终大于或等于源或目标 alpha 的方式组合 alpha 分量,但是仍然始终限制在 0 和 1 之间,就像源和目标 alpha 值一样。