在 glsl 着色器中合成两个 alpha 纹理

dar*_*ame 5 opengl-es fragment-shader libgdx

我希望在一个着色器中组合两个纹理,就像您对 Photoshop 之类的程序所期望的那样。也就是说,一种纹理叠加在另一种纹理之上,就好像分层一样。两个纹理都将具有 Alpha,并且结果输出也应具有正确的组合 Alpha。

所以目标是; 复合图像插图

然而,尽管用谷歌搜索公式,我无法得到正确的颜色。使用此处的参考:(https://microsoft.github.io/Win2D/html/PremultipliedAlpha.htm)例如产生;

在此输入图像描述

(注意灰色 50% 叠加的差异)

着色器代码在 libgdx 中设置以使用它作为混合;

  context.setBlending(true,GL20.GL_SRC_ALPHA ,GL20.GL_ONE_MINUS_SRC_ALPHA);         
Run Code Online (Sandbox Code Playgroud)

我相当确定错误出在我的片段着色器混合中(请参见上图中的代码),因为如果我将输入纹理 (A) 直接传递给 gl_FragColor,那么我会得到 A 的像素完美颜色匹配,包括其 alpha。
例如;

gl_FragColor = 反向漫反射;

工作正常。

=====

编辑

根据建议,我尝试使用预乘阿尔法代替。

context.setBlending(true,GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA); 
Run Code Online (Sandbox Code Playgroud)

然而,即使着色器刚刚设置为输出 A,这也会产生错误的效果

backdiffuse = texture2D(u_backSample2D, vTexCoord);     
backdiffuse=backdiffuse*backdiffuse.a; //convert to premultiply     
gl_FragColor =  backdiffuse; 
Run Code Online (Sandbox Code Playgroud)

我是否将 libgdxs 混合设置错误?这显然太亮了。

在此输入图像描述


解决方案(感谢接受的答案);

 backdiffuse.rgb *= backdiffuse.a; //premultiply source 
 v_backBackColor.rgb *= v_backBackColor.a; //premultiply source 

finalCol.rgb = backdiffuse.rgb + (v_backBackColor.rgb * (1 - backdiffuse.a));       
finalCol.a = backdiffuse.a + (v_backBackColor.a * (1.0 - backdiffuse.a));
Run Code Online (Sandbox Code Playgroud)

Ten*_*r04 2

如果要使用预乘 alpha 方程,还必须使用适当的混合方程将输出绘制到屏幕:GL_ONE、GL_ONE_MINUS_SRC_ALPHA。

并且目标 alpha 还必须乘以 1 减去源 alpha。所以:

finalCol.a = backDiffuse.a + v_backBackColor * (1.0 - backDiffuse.a);
Run Code Online (Sandbox Code Playgroud)

如果您想使用当前使用的更典型的混合方程,则着色器中的方程会更复杂。如果您在 Wikipedia 上查找alpha compositing,您就可以找到它们。然而,预乘 Alpha 是首选格式,因为它可以避免精灵的抗锯齿边缘上出现暗或亮条纹。