混合使用OpenGL ES不能像我认为的那样

时间:2015-10-20 00:32:38

标签: opengl-es alphablending

我把我的问题简化为绘制正方形来说明。我想绘制一个纹理,它将alpha通道从0到255逐渐淡化,然后垂直回到0,这样它就会与背景混合。现在它使背景变暗,我无法弄清楚原因。这是在iOS 9上使用OpenGL ES。

首先,我启用了我认为我想要的混合:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

然后我用绿色填充缓冲区:

glClearColor(0, 0.5, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

我有这个用作纹理的图像:

Texture

我使用GL_TRIANGLES绘制以下顶点({x,y,z},{r,g,b,a},{tx,ty}):

{{0.4, 0.3, 0}, {1, 0, 0, 1}, {0, 0}},
{{0.6, 0.3, 0}, {1, 0, 0, 1}, {1, 0}},
{{0.4, 0.5, 0}, {1, 0, 0, 1}, {0, 1}},
{{0.6, 0.3, 0}, {1, 0, 0, 1}, {1, 0}},
{{0.4, 0.5, 0}, {1, 0, 0, 1}, {0, 1}},
{{0.6, 0.5, 0}, {1, 0, 0, 1}, {1, 1}},

我希望顶点的红色成分调制纹理,因为这是我的片段着色器:

varying lowp vec4 DestinationColor;

varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;

void main(void) {
    gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut);
}

确实如此,但结果不仅仅是红绿色。它在边缘处变暗,我希望只绘制绿色:

Problem

类似问题here的答案说我应该使用glTexEnv(GL_BLEND)。但是,我认为这是一个OpenGL ES 1 API。

任何人都知道如何实现所需的混合效果?我希望红色在绿色上褪色。上衣和下衣应该是绿色的,而不是更深。不应该有明显的水平边缘。

编辑:我正在添加更多图片来说明我的问题。这是GIMP中的两个粉红点:

Pink dots in GIMP

当我将一个移到另一个上面时(在GIMP中),它们很好地融合在一起。它们也很好地融合了绿色背景:

Pink dots in GIMP, overlayed

当我在OpenGL ES中重新创建它时,我会变暗,这在粉红色点重叠的地方尤为明显。这次我做了一个非常狭窄的,所以你可以更好地看到效果:

Pink dots in OpenGL ES

我尝试了glBlendFunc和glBlendFuncSeparate,这导致了相同的效果。请注意,背景alpha为1。

2 个答案:

答案 0 :(得分:0)

您的问题很可能是显示Alpha通道本身,而不是颜色。由于您使用直接混合功能,因此它会将Alpha通道设置为低于1.0的值,然后您将其视为显示的预乘颜色值:RGB = RGB*A。您应该使用单独的混合函数来分别处理Alpha通道:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)

现在将按照您的预期混合颜色,但保持目标alpha值为1.0,并将其设置为清晰颜色。

答案 1 :(得分:0)

如果您的设备使用默认设置,假设像素数据是预乘的,那么您可能会得到类似您所看到的结果。我建议将您的Alpha通道图像转换为简单灰度,然后将其保存为PNG并验证它是灰度而不是BGRA格式。然后,以正常方式将每像素8位数据加载到纹理中,而不必担心任何预乘问题(灰度不包含和alpha通道)。接下来,通过从灰度测试中读取单个字节,然后将现有DestinationColor的3个分量乘以此线性alpha值,在着色器中执行预乘步骤。例如,这个预乘步骤让我的着色器在iOS上运行。