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

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

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

  • 从纹理显示原始像素颜色,v_Color变量设置为r = 0,g = 0,b = 0,a = 0
  • 或将原始像素颜色丢弃为v_Color中存储的颜色。如果我将v_Color中的alpha设置为1.0,则使用此值,在其他情况下,则使用原始像素的颜色。
  • 但是,如果我在具有alpha == 0.0的像素的图像上应用此着色器,则我在第二种情况下会遇到问题。我希望这些像素是不可见的,但它们也是彩色的。在第一种情况下,我没有这个问题。我需要舍弃alpha == 0

    的像素

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

    在程序开始时我设置了:

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

    这是我的片段着色器:

    1
    2
    3
    4
    5
    6
    7
    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 "的原因。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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进行了某些处理,它在某种程度上是透明的,但并不完全。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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;
    }

    enter

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

    当你做

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

    然后,如果c.a == 1.0,则丢弃纹理的Alpha通道,因为还从c中读取了Alpha通道。

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

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

    如果颜色应为黑色(即部分),其中纹理的alpha通道为0.0,则在混合之前,必须将颜色乘以纹理的alpha通道:

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

    但是请注意,由于纹理过滤的原因,可能会发生某些从纹理为红色的颜色完全透明的现象。如果希望输出颜色是完全不透明或完全透明,则必须将alpha通道与阈值进行比较。这可以通过glsl函数step完成,该函数返回1.0或0.0:

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