BinomialLLC / basis_universal

Basis Universal GPU Texture Codec
Apache License 2.0
2.7k stars 263 forks source link

Possible issue with alpha generation for certain shapes #337

Open kg opened 1 year ago

kg commented 1 year ago

Hi, I've been using basis to compress ability icons in my game and have noticed that certain geometric patterns cause really obvious square/angular artifacts in the resulting texture, at least when transcoded to BC7. The artifacts seem to mostly show up in generated mip levels and not in the base full-resolution level, which makes me think it could potentially be some sort of downscaling bug or otherwise indicate a problem in the encoder instead of just being a normal artifact.

Including a couple example images (showing the BC7 mips' channels with levels adjusted to make it obvious) and then I will attach the associated ktx files. They're all generated using the basisu.exe compressor with -uastc -ktx2 -mipmap -mip_srgb -mip_clamp -q 254 -comp_level 3 -uastc_rdo_l 0.6 settings. To my eye it looks like the problem is that the RGB channels have rectangular blocks of solid color around the colored shapes, and the hard transition between blocks is causing visible error in the alpha channel when scaled down since the hard transitions are no longer at block boundaries. I'm not sure if you could realistically fix this but it seems likely to affect real-world textures in a way that could be noticeable - for me, I'm generating outlines/drop shadows for these images which amplifies the visibility of the artifacts significantly. I may just find a way to clean them up with biases in the shader. Maybe the way downscaling works could be adjusted so that it will avoid preserving these blocks during the downscale and instead generate new natural block boundaries to avoid the artifacts?

image image isse-initiative-buff-party

image image isse-initiative-tether

I can also just store these icons as lower resolution RGBA at runtime, so this isn't a huge problem for me, but I figured I'd flag it since it seems to occur for many images instead of just one.

KTX files are in this ZIP: textures.zip

kg commented 1 year ago

Possibly useful extra info: If I configure the basis transcoder to generate RGBA textures from the ktx2, I can see the same artifacts in the color channels but the alpha is totally okay. So I guess that means this could be an issue with the transcoder, and not the original encoding process. image image

kg commented 1 year ago

BC3 also looks okay - it has the sort of artifacts I'd expect, but none of the weird rectangular ones. image

richgel999 commented 1 year ago

OK - I will experiment with your images and see what's going on.

kg commented 1 year ago

I tested a theory and it seems to have worked out: If I manually pre-process the images before encoding by setting all transparent pixels to solid black, it mostly prevents this problem. So the issue appears to be that when the artist authored the source images, the image editor produced a PNG where transparent pixels had RGB color values instead of black (that happened to be arranged in rectangular blocks) - I bet this decreases the size of the PNG, which is ideal for uploading them to the web or sending them via email. The color blocks seem to be causing these challenges for the transcoder, so eliminating them mitigates it.

It still seems like an undesirable effect but I think that makes this a subtle form of user error, since not all images basis compresses will have an association between rgb and a of this sort. The way the mips look still seems kind of wrong but I can imagine it being unavoidable.

One option would be for basisu to have a switch that informs it that the source image's rgb and a channels are linked so it can do this transform itself, but that feels like it might be unnecessary scope creep. It would probably improve quality for many users who don't know they have this problem, though! Right now I'm introducing a pre-processing pass that does this cleanup and also crops transparency out of images to reduce my memory usage, so that option will not be as useful to me, but I suggest it since it might help other users avoid/mitigate this problem more easily. Of course, they'll still need to do x.rgb * x.a in their shaders at runtime, but basisu can't fix that.

richgel999 commented 1 year ago

Thanks for the update.

One option would be for basisu to have a switch that informs it that the source image's rgb and a channels are linked so it can do this transform itself, but that feels like it might be unnecessary scope creep

It's super challenging to support all the formats, and all the different ways alpha channels are used.