繁体   English   中英

opengl es2预乘与直接alpha +混合

[英]opengl es2 premultiplied vs straight alpha + blending

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

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

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

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

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

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

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

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

元素很好地淡化和淡化。 但是白色元素上的任何白色都有一个看起来像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);
}

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

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

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

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

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

更新:

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

gl_FragColor.rgb *= glFragColor.a;

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

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

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

使用直线α来创建纹理通常是必要且首选的,但是在构建步骤的一部分或纹理加载期间将它们预先乘以比将它们保持为内存中的直线更好更好。 我不确定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);

您引用的常见直接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))。

AFAIK, glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 是预乘的alpha,如果按原样使用颜色,它应该可以正常工作。 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 是直的阿尔法。

许多纹理加载框架隐式地将图像转换为预乘的alpha格式。 这是因为他们中的许多人正在将图像重新绘制成新图像,而CGBitmapContext不支持直接(非倍增)图像。 因此,它们通常会生成预乘的α图像。 因此,请查看纹理加载代码,并检查它是否已转换为预乘格式。

此外,Photoshop(当然是Adobe的)在导出到PNG时隐式擦除完全透明(alpha = 0)像素上的颜色信息。 如果使用线性或其他纹理过滤,则GPU将对相邻像素进行采样,透明像素中的颜色将影响边缘处的像素。 但Photoshop已经删除了颜色信息,因此它们会有一些随机颜色值。

从理论上讲,可以通过在透明像素上保持正确的颜色值来修复这种颜色渗色。 无论如何,使用Photoshop,我们没有实用的方法来导出PNG文件并保持正确的颜色值,因为Photoshop不尊重隐形的东西。 (需要编写一个专用的PNG导出器Photoshop插件来正确导出它们,我不能很好地支持这个)

预乘alpha只是为了显示图像,但如果使用任何着色器颜色魔法它将无法正常工作,因为颜色以整数形式存储,因此它通常没有足够的精度来恢复原始颜色值。 如果您需要精确的颜色魔法物品,请使用直接alpha - 避免使用Photoshop。


更新

这是我在iPhone模拟器上的@ SlippD.Thompson测试代码的测试结果(64位/ 7.x)

 <Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 3-component color space; kCGImageAlphaNone; 2048 bytes/row.
    cgContext with CGImageAlphaInfo 0: (null)
    cgContext with CGImageAlphaInfo 1: <CGContext 0x1092301f0>
    cgContext with CGImageAlphaInfo 2: <CGContext 0x1092301f0>
 <Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaLast; 2048 bytes/row.
    cgContext with CGImageAlphaInfo 3: (null)
 <Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaFirst; 2048 bytes/row.
    cgContext with CGImageAlphaInfo 4: (null)
    cgContext with CGImageAlphaInfo 5: <CGContext 0x1092301f0>
    cgContext with CGImageAlphaInfo 6: <CGContext 0x1092301f0>
 <Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 0-component color space; kCGImageAlphaOnly; 2048 bytes/row.
    cgContext with CGImageAlphaInfo 7: (null)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM