OpenGL透明图像中含有黑色

5
我正在开发一款Android游戏,但当我使用透明度绘制图像时,似乎总会在透明部分添加一些黑色。这种情况经常发生,使我的一些效果看起来很奇怪。
以下是一个例子。两个圆只是带有模糊的白色图像,但你可以看到当它们重叠时,会产生阴影。如果我在Inkscape中重叠两个圆,它们重叠的部分会变成纯白色。 enter image description here 我正在使用
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

针对我的混合操作,有什么原因导致这种情况发生,我该如何避免它?

编辑:我唯一想到的是两个图片具有相同的 z 值,所以它们可能只与背景混合而不是互相混合?

编辑:

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

to

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_DST_ALPHA);

这是我寻找的结果。 输入图像描述 现在唯一的问题是忽略了我拥有的具有透明黑色的透明图像,这很合理,因为目标alpha为1。为什么源减去One加上灰色?

关于你编辑中的问题,你是错误的,那是不可能的。 - Tim
就我个人而言,我认为阴影看起来很棒。但那只是我的想法。 - ashes999
4个回答

11

我找到了解决办法。

我进行了更改。

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

事实证明,当你加载PNG图片的纹理时,Android会对其alpha值进行预乘(导致白色变成灰色)。

我添加了

vColor.r = vColor.r * vColor.a;
vColor.g = vColor.g * vColor.a;
vColor.b = vColor.b * vColor.a;

我希望将其他颜色乘以我的顶点着色器。


你可以将alpha除掉。请阅读我下面的评论。 - Петър Петров

1

您确定您的内容是正确的吗?如果您不希望圆圈产生任何黑色,则图像中的颜色值应完全为白色,并且alpha通道应定义圆圈的形状。现在看起来像是图像有一个白色圆圈,同时alpha通道和颜色值都逐渐减少到零,这会导致光晕。


是的,我的图像完全是白色的,模糊和形状由阿尔法通道定义。 - Lit Climbing
1
是的,但你使用的是哪个库?它肯定会预乘你的 alpha。 - Петър Петров

0

你是否使用了线性采样?我的想法是,如果你有一个非常小的图像(尺寸小于30-40像素),你可能会得到插值的alpha值,介于圆形内部(alpha = 1)和圆形外部(alpha = 0)之间。这将给你中间的alpha值,从而产生模糊效果。

当你绑定圆形纹理时,请尝试以下代码:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

也许你可以托管实际使用的纹理,以便我们可以检查它?如果这不起作用,请发布您的绘图代码。

我认为你不理解。 我想要模糊,它在原始图像中。 原始图像中没有的是它重叠的黑色部分。 我会在问题中发布原始图像。 - Lit Climbing
@EmbMicro 哦,抱歉我误解了。在原始图像中,你先画了哪个圆?如果你使用深度测试,你的深度缓冲区设置是怎样的? - Tim

0

你也可以通过alpha值进行除法运算,因为问题在于,当你导出纹理时,图像处理软件可能会对Alpha通道进行预乘。我最终在我的片段着色器中使用了alpha除法。以下代码是HLSL的,但你可以轻松地将其转换为GLSL:

float4 main(float4 tc: TEXCOORD0): COLOR0
{
    float4 ts = tex2D(Tex0,tc);

    //Divide out this pre-multiplied alpha
    float3 outColor = ts.rgb / ts.a;

    return float4(outColor, ts.a);
}

请注意,这种操作是有损的,非常有损,并且即使在这样的情况下可能已经足够了,它也不是一般解决方案。在您的情况下,您可以完全忽略COLOR,在片段着色器中提供原始的alpha和白色,例如return float4(1,1,1,ts.a);(转换为GLSL)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接