Opengl es 在OpenGL中混合ES并不像我认为的那样工作

Opengl es 在OpenGL中混合ES并不像我认为的那样工作,opengl-es,alphablending,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_BUF

我把我的问题简化为画一个正方形来说明。我想画一个纹理,它将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);
我将此图像用作纹理:

我用GL_三角形画以下顶点({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);
}
确实如此,但结果并不仅仅是红过绿。边缘变暗,我希望只画绿色:

类似问题的答案是我应该使用glTexEnv(GL_BLEND)。然而,我认为这是一个OpenGLES1API

有人知道我怎样才能达到理想的混合效果吗?我想让红色在绿色中消失。顶部和底部应为绿色,而不是较深。不应有明显的水平边缘

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

当我把一个放在另一个上面时(在GIMP中),它们很好地融合在一起。它们还与绿色背景完美融合:

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


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

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

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)

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

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

我对混合函数有点生疏,但你的屏幕截图看起来结果类似于Photoshop的“乘法”。我想你需要一个不同的混合函数,但现在不能完全回答哪一个…应该有一个常见混合函数的“备忘单”,作为参考…我使用这个混合函数是因为它被推荐为“正常”。GL_SRC_ALPHA,GL_ONE_减去_SRC_ALPHA意味着color_mided=color_SRC*ALPHA_SRC+color_destination*(1-ALPHA_SRC)。这就是我困惑的原因。假设alpha是0.1,红色是1,绿色是0.5,这些边应该是0.1(1,0,0)+(1-0.1)(0,0.5,0)=(0.1,0.45,0),对吗?如果打开一个颜色比较站点,将#1A7300(混合示例)与#008000(背景)进行比较,颜色就不会那么暗。是的,这是混合位图(精灵)时使用的函数之一,具体取决于位图是否具有“预乘alpha”(尽管我记不起这是哪一个)。另一个我认为在两个参数中使用GL_one(同样,不记得是哪一个)。请记住,
source
是传入值(您要覆盖的值),
destination
是帧缓冲区中已经存在的值:这是非常有用的信息,看起来是一种更好的混合方式。但我很遗憾地说,这对我没有任何影响。可能是因为你的纹理是从图像加载的,所以颜色是alpha预乘的吗?基本上,当您将图像转换为RGBA原始数据,并且颜色RGB与alpha相乘,生成着色结果时,也会发生相同的情况。尝试检查一些半透明的像素,如果RGB部分是相同的,或者是缩放的(它需要是相同的)好主意!我没有想到纹理本身可能有问题。我只是看了看,我正在使用(iOS常量)kCGImageAlphaPremultipliedLast将纹理绘制到内存中。我猜你几乎肯定找到了我问题的根源。我用kCGImageAlphaLast根本得不到任何数据,所以我会继续努力。我将很快回来验证这确实是解决方案。我已经确认问题确实是纹理。我还没有解决这个问题,但我会把你标记为正确的,因为我现在可以在调试器中清楚地看到这个问题。奇怪的是,你不能用“alpha last”创建。也许你应该添加一些你尝试过的变体代码,解释问题所在。