Search code examples
openglprocessingblending

Texture transparency with P3D


I’m currently coding a “Doom” clone, using P3D. I’m not using any external library. I’m having a weird artifact that happens when I’m using a masked texture. I’ve tried several methods to fix it, but to no avail :(. DISABLE_DEPTH_MASK suppresses the artifact, but then my sprite get sorted all wrong.

If anyone can point me in the right direction, I would really appreciate it! I’m so close to having a functional engine! (disregard the “doom” face and soldier sprites, of course, they are just temporary assets I’m using…)

artifact1
artifact1
As you can see, eventhough the mask is working (see the feet of the soldier) it’s leaving a huge black (background color) artifact behind.

artifact2
artifact2
When walking behind the quad, the artifact isn't too bad but still present.


Solution

  • You have to use/enable Blending. This technique is used if you want ot render a sprite which is not completely opaque , but has partly or completely transparent areas

    The soldier has be rendered at the end, after the environment of the scene is finished. The depth test has to be enabled.

    Enable blending before you render soldier sprite (texture) with the alpha channel.

    gl.glEnable(GL.GL_BLEND);
    gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA);
    

    And disable blending after:

    gl.glDisable(GL.GL_BLEND);
    

    Note, the "black" background of the soldier sprite has to have an alpha channel of 0.0 (completely transparent) and the alpha channel of the soldier itself has to be 1.0 (completely opaque). In common PNG images fulfill this.


    Explanation:

    At the point when the soldier is rendered, then the background has already been drawn and the background color (color of the environment) has been stored in the framebuffer.
    The blending function is:

    dest.rgba = dest.rgba * (1 - src.a) + src.rgba * src.a
    

    where dest.rgba is the color in the framebuffer and src.rgba is the color of the sprite.

    If the alpha channel of the sprite is 1.0 (src.a = 1.0; opaque), then

    dest.rgba = dest.rgba * (1.0 - 1.0) + src.rgba * 1.0
    
    dest.rgba = src.rgba
    

    If the alpha channel of the sprite is 0.0 (src.a = 0.0; transparent), then

    dest.rgba = dest.rgba * (1.0 - 0.0) + src.rgba * 0.0
    
    dest.rgba = dest.rgba