opengl es2预乘与直接alpha +混合

bad*_*sel 3 alphablending opengl-es ios

在iphone上的Opengl es2.一些对象由多层精灵与alphas组成.

然后我也有UI元素,它们也是由各种精灵组合在一起的,我淡入/淡出其他一切.我通过调整着色器中的alpha来淡化.

我的纹理是PNG与alphahop中制作的alpha.我没有故意为他们做好准备.我希望它们是直的alpha,但在我的应用程序中,它们表现得好像它们被预先乘以我可以看到在白色背景上绘制的白色精灵周围的黑色边缘.

如果我将混合模式设置为:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

这些元素很好地融合在一起,没有奇怪的边缘.但是当元素逐渐消失时,它们最终会成为POP.它们将开始消退但不会一直下​​降到alpha零.所以在淡出动画结束时,当我删除元素时,它们"弹出"会导致它们没有完全消失.

如果我将混合模式切换为:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

元素很好地淡化和淡化.但是白色元素上的任何白色都有一个看起来像alpha预乘的暗边缘.查看白框顶部绘制的白色圆圈:

在此输入图像描述

但是场景中的其他混合物对我来说很好看.其他透明物体很好地融合在一起.

另一个重要的注意事项是我的着色器处理元素和颜色元素的不透明度.对于绘制的每个东西,我乘以元素颜色,最后的alpha乘以不透明度值:

void main(void)
{
    gl_FragColor = texture2D(u_textureSampler,v_fragmentTexCoord0);
    gl_FragColor = vec4(gl_FragColor.r*u_baseColor.r,gl_FragColor.g*u_baseColor.g,gl_FragColor.b*u_baseColor.b,gl_FragColor.a*u_baseColor.a * u_opacity);
}
Run Code Online (Sandbox Code Playgroud)

这允许我在我的精灵表中拍摄一个白色物体,并使其成为我想要的任何颜色.或者使用灰色的baseColor使对象变暗.

每当我想到我理解这些混合模式时,我就会开始怀疑自己.

是否有其他混合模式组合在我的精灵上有光滑的边缘,并且还支持着色器中的alpha淡化/混合?

我假设需要GL_SRC_ALPHA在着色器中使用alpha进行混合.

或者我的问题是我需要使用除PSD以外的东西来保存我的精灵表吗?因此在这一点上几乎是不可能的.

更新:

我认为答案可能只是否定,没有办法做我想要的.第二种混合模式应该是正确的.但它有可能是将RGB与某个地方的alpha相乘,或者它在源文件中被预乘.我甚至尝试通过添加以下内容在上面的着色器中预先复制alpha:

gl_FragColor.rgb *= glFragColor.a;
Run Code Online (Sandbox Code Playgroud)

但这只会使衰落看起来很糟糕,因为当它们逐渐淡出时,它们会变成灰色.如果我自己预先设定alpha并使用上面的其他混合模式,那么事情看起来和我原来的一样.它们在没有弹出的情况下逐渐消失,但你仍然可以看到光环.

Dav*_*vid 5

这是一篇关于如何避免带有直纹alpha纹理的黑条纹的精彩文章http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/

如果你正在使用mip-maps,这可能就是你的直线alpha纹理有黑条纹的原因 - 过滤直线alpha图像会导致这种情况发生,最好的解决方案是在mip-maps之前预先乘以图像.创建.有一个常见的黑客修复,如该文章中所述,但认真考虑预乘.

使用直线alpha来创建纹理通常是必要且首选的,但是在构建步骤的一部分或纹理加载期间将它们预先乘以比将它们保持为内存中的直线更好更好.我不确定OpenGL ES,但我知道WebGL允许你在加载期间通过gl.pixelPorei和gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL参数在运行中预加倍纹理.

另一种可能性是,如果你要合成许多元素,你的直接alpha混合函数是不正确的.为了使用直接alpha图像做一个正确的"over operator",你需要使用这个混合函数,也许这就是你要找的东西:

gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

您引用的常见直接alpha混合函数(gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA))无法正确处理目标Alpha通道,在混合直接alpha图像源时,必须使用单独的颜色和alpha混合函数,如果您打算使用"over运算符"合成多个图层.(想想你可能不想插入alpha通道,它应该总是比source和dest更不透明.)并且在混合时要特别小心,因为直alpha混合的结果是预乘图像!因此,如果您稍后使用结果,您仍然必须准备好进行预乘混合.对于更长的解释,我在这里写了这篇文章:https://limnu.com/webgl-blending-youre-probably-wrong/

使用预乘图像和混合的好处是你不必为颜色和alpha使用单独的混合函数,并且你自动避免了很多这些问题.你可以&应该创建直的alpha纹理,但是在加载之前或加载期间预加倍,并在整个代码中使用复合混合(glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA)).