Alpha Mask shader using PKM compressed texture ETC1 format RGB888 - artifacts


I’ve spent many weeks trying to solve this problem by trawling through google and have since been unable to resolve the issue.

I am a mobile developer and I ran in to the issue of running out of memory and poor performance for the Android platform using OpenGL ES 2.0, that was when I became aware of compressed textures. The PVR format for iOS solved all my problems there. However there is not such a simple alternative for Android. The only compressed texture format supported on all devices is ETC1. Great so I can utilize ETC1 to get increased performance and reduced memory usage.

Not so great… :doh: the ETC1 texture format does not support the alpha channel, so I had to solve this problem differently. A common approach is to provide the alpha channel of an image as an alpha mask in a separate compressed texture stored in one of the RGB channels. So there would be one texture (.pkm) that contains the real RGB values of the opaque parts of the image and another separate texture (.pkm) that contains the alpha channel.

Thankfully there is a tool that does exactly this and separates a png for example in such a way. Mali texture compression tool.

So with a bit of effort and research I was able to create a shader that took the RGB channels from one texture sampler and created a color from that and then another texture sampler for the alpha mask which took the alpha from one of the rgb channels and put it in the alpha channel for the new colour.

I then discovered that my Blend function was wrong, I changed this to (GL_SRC_ALPHA, GL_ONE_MINUS_SOURCE_ALPHA)

So I have nearly the desired effect, if you’ve read this far here is the problem:

I am getting small white line artifacts around the edges where the alpha begins. I’m not sure if maybe the blend function is wrong or it is something to do with the fact that the rgb texture sets all the alpha parts to white which could be bleeding in somehow. Maybe I need to pre multiply the alpha somewhere, not sure how I’d do that with this setup. I’ve attached an example as a visual aid.

Example textures:

Vertex shader:

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
    gl_Position = CC_PMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;

Fragment shader:

#ifdef GL_ES
precision mediump float;

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

//uniform sampler2D u_diffusetexture;
uniform sampler2D u_texture1;

void main()
    vec4 color1 = texture2D(CC_Texture0, v_texCoord);
    vec4 color2 = texture2D(u_texture1, v_texCoord);
    vec4 color3 = vec4(color1.rgb, color2.g);

    gl_FragColor = color3;

Changing the completely-transparent pixels from white to match the colour of the other non-transparent pixel(s) within a 4x4 would probably improve matters.

Using pre-multiplied alpha would probably make matters worse, as it would tend to increase the amount of variation within the colour channel

I solved this issue after speaking with some experts from the ARM Mali graphics department on their forums. The solution is to generate a .pkm texture with pre multiplied alpha, you still need to provide the alpha channel (mask) separately in another texture using shaders to combine the two. Then you need to set the blend function to (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) for pre multiplied alpha. This fixes all the artifacts you might see.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.