Opengl ES 2.0 着色器 - 丢弃 alpha == 0 的像素而不丢弃,如果

Opengl ES 2.0 shader - discard pixels with alpha == 0 without discard and if

我的片段着色器做了两件事:

  1. 显示纹理的原始像素颜色,v_Color 变量设置为 r=0,g=0,b=0,a=0
  2. 或丢弃原始像素颜色为存储在v_Color中的颜色。如果我将 v_Color 中的 alpha 设置为 1.0,则采用此值,在其他情况下使用原始像素的颜色。

但是在第二种情况下,如果我将此着色器应用于具有 alpha == 0.0 像素的图像,我会遇到问题。我预计这些像素是不可见的,但它们也是彩色的。在第一种情况下,我没有这个问题。我需要丢弃 alpha == 0

的像素

例如: 我有应该着色的人物剪影纹理,但应该跳过透明像素。

程序开始时我设置:

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

这是我的片段着色器:

void main()
{
    vec4 c = vec4(v_Color);
    vec4 p = texture2D( s_texture, v_texCoord);

    gl_FragColor = mix(p, c, c.a);
}

但是,如果我添加 discard,那么一切都会像预期的那样工作。 alpha==0.0 的像素被移除。但我正在使用 OpenGL ES 2.0,着色器将 运行 跨不同的 android 设备,我阅读了 "if" 和 "discard" 可能导致的性能问题。这就是为什么我使用 "mix" 而不是 "if".

void main()
{
    vec4 c = vec4(v_Color);
    vec4 p = texture2D( s_texture, v_texCoord);

    if (p.a == 0.0) {
        discard;
    }

    gl_FragColor = mix(p, c, c.a);
}

我尝试了另一种尝试来解决这个问题。我记得来自纹理的原始 alpha,我在最后应用它。但它仍然给我奇怪的结果。 gl_FragColor.a = backup_alpha 对结果 alpha 做了一些事情,它在某种程度上是透明的但不完全。

void main()
{
    vec4 c = vec4(v_Color);
    vec4 p = texture2D( s_texture, v_texCoord);
    float backup_alpha = p.a;

    gl_FragColor = mix(p, c, c.a);
    gl_FragColor.a = backup_alpha;
}

感谢@Rabbid76 的帮助,这是正确的:

gl_FragColor = vec4(mix(p.rgb, c.rgb*p.a, c.a), p.a);

当你这样做时

gl_FragColor = mix(p, c, c.a);

然后丢弃纹理的alpha通道,如果c.a == 1.0,因为alpha通道也是从c读取的。

您必须混合纹理和颜色的 .rgb 分量,但您必须使用纹理的 alpha 通道(无论如何)来解决问题:

gl_FragColor = vec4(mix(p.rgb, c.rgb, c.a), p.a);

如果颜色应该是黑色,那部分,纹理的alpha通道是0.0,那么在混合之前颜色必须乘以纹理的alpha通道:

gl_FragColor = vec4(mix(p.rgb, c.rgb*p.a, c.a), p.a);

但是请注意,由于纹理 filtering, it may occur, that some colors which are red from the texture are nit completely transparent. If you want that the output color is either completely opaque ore completely transparent, then you've to compare the alpha channel to a threshold. This can be done by the glsl function step,returns 要么是 1.0 要么是 0.0:

gl_FragColor = vec4(mix(p.rgb, c.rgb, c.a), step(0.5, p.a));