我经常发现OpenGL,当我试图在纹理上绘制一些东西,然后再到另一个表面上,使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
,我总是以彩色晕(通常是暗色带)结束,在我的源图像的半透明部分附近的边缘。这显然是由于制作由这种混合风格引起的本质上是预乘法alpha的问题造成的。对于3d场景,我通常使用画家算法,而对于渲染2d内容,我喜欢先绘制最后面的对象,然后在它们上面叠加额外的对象。值得注意的是,在做这样的2d绘图时,我通常不能像在3d中那样依赖于z缓冲区这样的功能,这就是为什么渲染像gui这样的东西比渲染3d场景图形更有问题的原因
我认为值得注意的是,当目标缓冲区恰好已经完全不透明时,上述混合风格实际上是完美的,但如果目标是透明的,那么在这种情况下真正需要的是glBlendFunc(GL_SRC,GL_ZERO)
..因为任何全白像素,部分透明的来源,例如,应该保持完全饱和的颜色,而不是"混合"的背景,实际上还不存在,因为使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
实际上会渲染部分透明和全白像素作为前景和背景之间的混合,这是我想要的,但不是alpha信息丢失的程度,也不是颜色实际改变的程度。
因此,在我看来,这种混合函数可能是完美的,它实际上是由glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
引起的和由glBlendFunc(GL_SRC,GL_ZERO)
引起的,这取决于DST_ALPHA
本身的值。
因此,理想的情况是:
Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad
Ar = As * (1 - Ad) + Ad * Ad
这样,如果目标已经是不透明的,正常的alpha乘法适当地混合,而如果目标是透明的或部分透明的,它将使用更多的源图像的真实颜色,而不是使用alpha预乘法形式的颜色。
然而,似乎没有明显的方法来描述这种混合机制的OpenGL。这样的问题似乎不应该是我所特有的,而且对我来说更不寻常的是,似乎没有任何方法可以实现这一点……即使在可编程管道中。
到目前为止,我发现的唯一解决方案是每当我绘制到我将在其他地方绘制的纹理时,反转绘制顺序,并使用glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA)
。
在这种情况下,我在纹理上绘制一些东西,稍后将正常渲染,这是一种妥协,但这对我来说是没有吸引力的,因为它缺乏可重用性,除非绘图的代码总是知道目的地的类型是什么,这样它就可以逆转它自己通常的绘图顺序,我可以使它不必要地复杂化。
最后,尽管颠倒整个场景的绘制顺序并非完全不可能做到,但它要求在绘制第一个对象之前确定将在图形的每一帧中显示的完整对象列表。我所面临的核心问题是,虽然这在渲染3D场景时是可行的,但当绘制2d gui时,所绘制的事物及其绘制方式的多样性是如此之大,以至于没有办法将它们概括成一个单一的对象列表,之后总是可以按反向顺序遍历。在我看来,对于如何以这种"向后"的顺序构建2d场景,这似乎需要一种与我习惯的完全不同的观点,以至于我目前甚至无法理解一个可维护的解决方案。
所以…还有别的办法吗?我错过什么了吗?还是我必须学习一种完全不同的方式来构建二维图像?我不可能是唯一一个有这个问题的人,但我还没有找到任何好的、干净的解决办法。
编辑:如果确实存在任何通用的OpenGL扩展,由NVIDIA或其他方式,允许混合模式可以做到这一点:
Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad
Ar = As * (1 - Ad) + Ad * Ad
(其中Cs和Cd是源和目标颜色,As和Ad是源和目标alpha值,Cr和Ar是结果颜色和alpha值),我真的很想知道扩展名为什么,以及如何使用它…
我写过各种各样的东西,将半透明的2D叠加到半透明的3D内容上,从来没有觉得OpenGL在glBlendFunc
/glBlendFuncSeparate
领域缺少一些关键的东西(至少在你开始担心sRGB内容和framebuffer的伽马校正合成之前)。
我主要怀疑你使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
显然与预乘alpha(对不起,虽然你的问题很长,我实际上并没有发现它那么清楚;一些简单测试用例的图像可能会有所帮助)。对于合成预乘alpha内容,我希望看到GL_ONE
作为glBlendFunc
参数之一(哪一个取决于您是否在进行over/under操作)。
有一个关于混合/合成的非常好的幻灯片(包括正确使用预乘法和。"直"色)在这里(幻灯片20-35的相关材料)。
(尽管我声称现有的已经足够好了……值得一提的是,NVidia最近在这方面添加了一些新功能)。