0

我的应用程序使用 8888 格式的全屏 glSurface 覆盖。对于大多数设备来说,这工作得很好——我可以使用 OpenGL ES 绘制半透明图像,这确实会在我的其他本机视图之上覆盖透明度。

然而,在 Nexus 10 和 Note 2(很可能还有其他一些设备)上,半透明像素在物理显示器上看起来并不正确,即使通过 DDMS 截取的屏幕截图看起来绝对正确!这让我很困惑 - 视觉显示与屏幕截图有何不同?

对于帧缓冲区中 alpha 值不是 1 (0xff) 或 0 (0x00) 的任何像素,似乎都会出现这种奇怪现象。

我附上了来自 Nexus 10 的 DDMS 屏幕截图,显示了一张完全符合其应有的测试卡图像。我还附上了显示器上的一张照片,显示了一个非常不同的图像......如上所述,EGL 覆盖 alpha 值不是 0x00 或 0xff 的像素似乎显示不正确。注 2 相同。

有谁知道如何解决这个问题?这对我们来说是一个主要障碍,因为我们甚至不知道以编程方式确定设备显示屏是否出现问题的方法。

Nexus 10 显示照片,看起来不正确 Nexus 10 DDMS 屏幕截图,看起来正确

4

1 回答 1

1

Android 上的半透明窗口应包含预乘 alpha 的颜色。窗口合成器使用的混合方程为:

dest.rgb = src.rgb + dest.rgb*(1 - src.a)

有效的预乘颜色始终具有 color.rgb <= color.a。如果不是这种情况,则混合方程的结果可能大于 1.0。在 OpenGL ES 中,如果您尝试写入大于 1.0 的颜色,它将被限制为 1.0(除非您正在渲染到浮点颜色缓冲区)。因此,无效的预乘颜色在 GL 渲染中或当窗口合成器使用 GL 进行合成时通常不会被注意到。

但是,Android 并不要求具有专用合成硬件的设备(如今几乎所有的 Android 设备)在混合溢出时钳制到 1.0。大多数设备都有钳位功能,但 Nexus 10 中的 Exynos 5250 没有;它以 8 位定点进行混合数学运算,并在溢出时换行 (0xFF + 0x2 == 0x01)。如果 Note 2 中的 Exynos 4412 的行为方式相同,我不会感到惊讶。

要解决此问题,您需要在帧末尾的帧缓冲区中具有有效的预乘颜色。许多应用程序,包括 Android UI 框架,通过确保预乘任何非透明输入(纹理、顶点颜色等)来做到这一点——之后大部分数学运算都会自动计算出来。如果您不能确保预乘输入,您可以添加

gl_FragColor.rgb *= gl_FragColor.a;

到片段着色器的末尾。如果您进行任何混合,则需要调整您使用的混合方程/因子。

于 2014-03-28T03:27:17.050 回答