3

iphone上的opengl es2。一些对象是由具有 alpha 的多层精灵组成的。

然后我还有 UI 元素,这些元素也是由各种精灵组合在一起的,我在其他所有东西之上淡入/淡出。我通过调整着色器中的 alpha 来进行淡入淡出。

我的纹理是在 Photoshop 中制作的带有 alpha 的 PNG。我不是故意的。我希望它们是直接 alpha,但在我的应用程序中,它们表现得好像它们是预乘的,我可以看到在白色背景上绘制的白色精灵周围的暗边。

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

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

元素很好地组合在一起,没有奇怪的边缘。但是当元素淡出时,它们会在最后弹出。它们将开始褪色,但不会一直下​​降到 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 并使用上面的其他混合模式,事情看起来和我原来的一样。它们在没有弹出的情况下淡出,但您仍然可以看到光晕。

4

2 回答 2

5

这是一篇关于如何使用直 alpha 纹理避免深色边缘的精彩文章http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/

如果您使用的是 mip-maps,这可能就是为什么您的直 alpha 纹理具有深色边缘的原因——过滤直 alpha 图像会导致这种情况发生,最好的解决方案是在 mip-map 之前预乘图像创建的。在那篇文章中也描述了一个常见的黑客修复,但请认真考虑使用预乘法。

使用直接 Alpha 来创建纹理通常是必要且首选的,但作为构建步骤的一部分或在纹理加载期间将它们预乘比将它们作为直接 Alpha 保存在内存中仍然更好。我不确定 OpenGL ES,但我知道 WebGL 允许您在加载期间通过使用带有 gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL 参数的 gl.pixelStorei 动态预乘纹理。

另一种可能性是,如果您正在合成许多元素,则您的直接 Alpha 混合功能不正确。为了对直接 alpha 图像进行正确的“过度操作”,您需要使用此混合功能,也许这就是您要寻找的:

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 通道,它应该总是比源和目标更不透明。)混合时要特别小心,因为直接 alpha 混合的结果是预乘图像!因此,如果您稍后使用结果,您仍然需要准备进行预乘混合。对于更长的解释,我在这里写了这个:https ://limnu.com/webgl-blending-youre-probably-wrong/

使用预乘图像和混合的好处是您不必为颜色和 alpha 使用单独的混合函数,并且您会自动避免很多这些问题。您可以并且应该创建直接的 alpha 纹理,然后在加载之前或期间对其进行预乘,并在整个代码中使用 premult 混合 (glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA))。

于 2016-06-16T20:45:29.410 回答
3

AFAIK,glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);用于预乘 alpha,如果您按原样使用颜色,它应该可以很好地工作。glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);用于直接阿尔法。

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

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

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

预乘 alpha 足以显示图像,但如果您使用任何着色器颜色魔法,它就不会很好地工作,因为颜色以整数形式存储,因此它通常没有足够的精度来恢复原始颜色值。如果您需要精确的色彩魔法,请使用直接 alpha — 避免使用 Photoshop。


更新

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

 <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)
于 2014-04-23T22:45:45.997 回答