Hello,
I'm having a problem when creating textures with the Mali texture compression tool. I'm following this Mali tutorial to create a separate alpha mask that handles the alpha channel from an ETC1 texture using Method 2 as described. I managed to get this working but it appears that little white lines or artifacts are appearing round the edges where the alpha parts of the image meet the opaque parts. My current blend function is (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). This was the only blend function that would allow this to method to work. Maybe there is another blend function that would change this and rectify the problem. Or maybe some other setting in OpenGL, I aslo posted this on the OpenGl forums.
I think the problem may go away or be less noticeable if the first generated texture that contains the real RGB values has black for the transparent areas instead of white. Mali Compression tool sets the alpha areas to white and there is no option to change this in the tool. I also noticed that in the texture compression tool Texture Packer. When you generate .pkm files with that tool it sets the alpha areas to to black, which further supports this theory. As it is such a simple change, it would be great if the people who develop Mali could realease an update that allows you to set the colour of the transparaent areas in the generated image.
If anyone has any other insight on this problem that would be great.
EXTRA INFO:
OpenGL ES 2.0 (only supports etc1 not etc2)
Update:
I have since tested this with .pkm file generated from Texture Packer https://www.codeandweb.com/texturepacker. It does seem to make the problem almost unnoticeable (alpha pixels are set to black). But I think it's dependant on having dark backgrounds in a game. As all my backgrounds are dark I can't notice any artefacts. So in summary:
Mali GPU Texture Compression Tool
1. Please allow the developer to set the colour of the transparent pixels before the textures are generated.
2. There is a really nice feature called Trim in Texture Packer that allows the developer to set an alpha threshold, let's say 5 for example. All pixels with a transparency below 5 are set to fully transparent. This really helps with border artefacts too. Not too hard to implement.
Thanks.
p.s. Why not use Texture Packer? Well the answer to that is because the algorithm they use to generate the .pkm textures results in a much larger loss of image quality in comparison to Mali's tool. So I would rather use Mali if they can fix these problems.
The white borders you have are basically hitting a problem with post-multiplied alpha blending (which is how the API-level filtering and blending in OpenGL ES works, because it is fast and inexpensive to do in hardware). If you store textures using the normal post-multiplied approach the typical "buggy" behaviour is explained by the following example:
Imagine two neighbouring pixels [1.0, 0.0, 0.0, 1.0] (red, fully opaque) and [0.0, 0.0, 1.0, 0.0] (blue, fully transparent). If you sample in the mid point with bilinear filtering then you would logically expect "half transparent red" but because the channels are blended independently you would end up with half transparent purple [0.5, 0.0, 0.5, 0.5] even though the original blue color is never actually visible because of the transparency.
The fix to this is a technique called pre-multiplied alpha; simply multiply the RGB channel values by the A channel value before compressing them. As you imply this should mean black for areas where A is 0.0, but it will also scale colors in areas which are partially transparent.
As far as I can tell the Mali Texture Compression Tool doesn't do this, but you can do it easily enough using ImageMagick. The necessary command line is:
convert <original_texture.png> -write mpr:temp -background black -alpha Remove mpr:temp -compose Copy_Opacity -composite <premultipled-texture.png>
... and you can just compress the output texture "as normal" using the texture compression tool.
IMPORTANT It's worth noting that this fix isn't transparent to the application logic - you will need to "correct" the OpenGL ES blend equation for any alpha blended fragments (as well as any manual blending you do in shader code) if you want to keep the weighting of the color channels correct, because the source alpha has already been factored in due to the pre-multiplication. Set the source alpha in the blend equation to GL_ONE rather than using the alpha value out of the texture.
@ lorenzodalcol supporting this in MTC seems like a useful idea.
HTH, Pete
The best way to fix this is by propagating the color values out into the alpha space.
Since you're using a separate alpha channel, the color of the pixels is irrelevant to their transparency, so you can just as easily have transparent black pixels or transparent white pixels. But right at the edge that color shows through where the soft alpha mixes with the color, as Pete said.
Here is an alpha texture from one of our demos and I've gove over a blob with the un-erase tool:
As you can see where the alpha channel has been removed, the texture just continues out into the image. That way when the alpha starts blending out the colors at the edge of the texture stay the same.
stacysmith you're right that would be the most accurate fix for the current method. My fix is slightly more simple but less accurate, since if you just set the colour of all the entire alpha space in one go, to maybe a colour that roughly matches your background colour then the part where the soft alpha mixes with the colour would be barely noticeable.
Also that technique looks somewhat time consuming unless there is a program that can propagate the colours for you?
peterharris pre-multiplied alpha does seem like the solution I'm looking for, I know roughly how it works but I'm not an expert on subject by any stretch of the imagination. I'm pretty sure this is the blend function for pre multiplied alpha {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}? So the steps to take with pre multiplied alpha would be:
1. Obtain pre-multiplied alpha texture (.png)
2. Compress the texture "as normal"? so I can discard the alpha channel now that the alpha data is multiplied in to the rgb channels? No need for a separate alpha mask?3. Set the blend function to {GL_ONE, GL_ONE_MINUS_SRC_ALPHA} cocos2d-x: BlendFunc Struct Reference with I assume blend equation GL_FUNC_ADD4. Alpha should be drawn transparent as expected?
One more thing +1 to supporting this in MTC, I'm already running my texture through 2 different programs, adding another one to that list is going to be so time consuming, especially considering the amount of textures I have in my project. It would be great if MTC could output the compressed texture with pre multiplied alpha. I think developers would very much appreciate that.
1. Obtain pre-multiplied alpha texture (.png) 2. Compress the texture "as normal"? so I can discard the alpha channel now that the alpha data is multiplied in to the rgb channels? No need for a separate alpha mask?3. Set the blend function to {GL_ONE, GL_ONE_MINUS_SRC_ALPHA} cocos2d-x: BlendFunc Struct Reference with I assume blend equation GL_FUNC_ADD4. Alpha should be drawn transparent as expected?
You still need the source alpha channel to be stored in the compressed asset (as the blend uses GL_ONE_MINUS_SRC_ALPHA, even though it doesn't use GL_SRC_ALPHA). Other than that, what you have there looks correct.
peterharris Yea I realized that yesterday when I was playing around with the compressed textures from Texture Packer, that has an option for pre multiplied alpha. I suppose it kinda make sense because the program has no way of knowing what alpha values were multiplied in to the RGB channels. So I guess that solves everything.
So in summary it would be great if MTC could support pre multiplied alpha, any ETA on when that might be?
Regards,
Mark
Quick ways to implement this kind of thing depend on the nature of the texture you're working with before conversion, and how many files you need to convert,
If it's just one or two and you have the file with the transparency, using an alpha aware graphics tool like gimp you should easily create blurred offset layers behind the original, merge them all together, then mask it by the alpha channel of the original picture.
If you've got a lot of files, I'd recommend cracking out libpng and writing a tool to load in files and automatically propagate color values into semi-transparent pixels from adjacent more opaque ones.
-Stacy