渲染具有透明度的纹理时,OpenGL不需要的像素

时间:2016-01-12 15:33:08

标签: c++ qt opengl

我一直在努力解决这个问题。当我使用OpenGL渲染2D纹理时,在无透明度和一些透明度之间的过渡上具有透明度值,我得到一些恼人的灰色像素,我认为这是像素值插值的产物。关于如何改进的想法?

我附上一张图片来举例说明我在说什么: Red arrows show some of the parts where the unwanted pixels are visible

不是我认为它会有所作为,但我正在使用Qt来创建QGLWidget和C ++。

解决:

我一直试图解决这个问题。我尝试使用带有预乘Alpha通道的图像,使用单独的颜色和alpha混合函数...对我来说没有任何效果,我可能做错了,我不知道。对我来说,使用抗锯齿导出 .png 图像是有效的:Adobe Illustrator上的类型优化(提示)并使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

希望这有助于解决同样问题的其他人:)

再次感谢你的帮助。

1 个答案:

答案 0 :(得分:3)

简短的回答:Nicol Bolas是对的,你应该调查预乘的alpha,这是解释原因的数学。

为什么它无法正常工作

以下是非预乘alpha的工作原理。

将源纹理与颜色和alpha(C S ,α S )合成到目标(C D ,α< sub> D ),你得到公式:

  

C =α S C S +(1 - α S )C D

现在,如果我们有第二层纹理,首先(C 1 ,α 1 )然后(C 2 ,α 2 ),我们得到公式:

  

C =α 2 C 2 +(1 - α 2 )(α 1 C 1 +(1 - α 1 )C D

如果我们想要使用预合成纹理一步完成此操作,就像渲染到纹理一样,我们需要重新排列此公式以匹配原始公式:

  

C =(α 2 C 2 +(1 - α 2 )α 1 C 1 )+(1 - α 2 )(1 - α 1 )C D

     

α S C S 2 C 2 +(1 - α 2 < / sub>)α 1 C 1

     

(1 - α S )C D =(1 - α 2 )(1 - α 1 )C D

我们可以求解α S

  

α S = 1 - (1 - α 1 )(1 - α 2 )=α 1 2 - α 1 α 2

但是当我们解决C S 时:

  

C S =(α 2 C 2 +(1 - α 2 )α 1 C 1 )/(α 1 2 - α 1 α 2

没有OpenGL混合模式可以让我们正确地计算C S

如果alpha预乘?

预乘Alpha混合的公式不同:

  

C = C S +(1 - α S )C D

有两个纹理,

  

C = C 2 +(1 - α 2 )(C 1 +(1 - α 1 )C D

当我们重新排列以匹配第一个公式时,我们得到:

  

C = C 2 +(1 - α 2 )C 1 +(1 - α 2 )(1 - α 1 )C D

然后我们解决:

  

α S = 1 - (1 - α 1 )(1 - α 2 )=α 1 2 - α 1 α 2

     

C S = C 2 +(1 - α 2 )C 1

这与:

相同
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

因此,如果你对所有纹理使用预乘的alpha,那么所有数学运算都很完美,你不必担心这些东西。只需在任何地方使用相同的混合函数,在任何地方使用预乘的alpha,你可以按照自己喜欢的顺序组合事物。

预乘的alpha也会正确插值,但非预乘alpha不是这样,但这是一个单独的问题。

摘要

预乘的合成运算符是 associative ,这意味着你可以采用一堆图层并将它们压缩成一个纹理,完全按照你想要的方式。

如果没有预先乘以的alpha,数学就不会按照你想要的方式运行。