0
\$\begingroup\$

This question is about Unity texture compression.

I have an image that has the dimensions as follows: width = 724, and height = 1044. The original size is 348 Kbytes. This means that both the width and height are multiple of 4.

If I open this image in Unity, change the type to sprite (2D and UI), and set the max size to 2048, then Unity rendered this image with the size of 0.7 M, which is bigger than the original size of 348 Kbytes.

If I open this image in Unity, change the type to sprite (2D and UI), and set the max size to 1024, then Unity displays a strange warning as follows "Only textures with width / height being multiple of 4 can be compressed to ETC2 format", and it does not compress this image even though I believe that both the width and height of this image are already multiple of 4 because as I wrote earlier, the dimensions of the image are as follows: width = 724, and height = 1044.

Would you please show me how to fix that warning message above ?

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

It's not unusual for the "compressed" sizes of game textures to be larger than the source asset files, because the compression formats we use at runtime in games need to be GPU-readable.

I go into more detail about this in other answers, but to be brief:

  • Typical compression formats we use for source assets or images on the web (PNG, JPG) can use variable bit rates: taking predictable areas of the image and compressing them more, while complex parts of the image use more raw data. They're also decompressing the whole image at once, so they can use information from one part of the image to make predictions to better compress other parts of the image.

  • When rendering an image with a GPU, you need random access. A shader core needs to be able to ask "What's the colour at pixel (154, 1011)?" and the texture unit needs to know the exact position in memory to find that and be able to answer the question fast, without taking the time to read distant parts of the image to work out the correct decompression table.

That unfortunately means compression for game assets isn't as good by many metrics as PNG/JPG. We generally have to deal with larger memory footprints, and as we try to crunch down the file size we see visible quality loss much faster, because the more aggressive compression algorithm hits all parts of the image, not just the smooth compressible parts.

For that reason, images that are very sensitive to being displayed just-so, like 2D sprites and UI images, will be saved in an uncompressed format, so you don't get the visual degradation that comes with GPU texture compression. That's why changing the image type to "Sprite (2D and UI)" makes the file size double in your case.

0.7 MB is still not that bad in an era when GPU have gigabytes of fast video RAM, and even most phones have access to multiple gigabytes of shared RAM, but it can add up over a large game, or if you're trying to really crunch your download size. See advice for reducing Unity build size, including use of asset bundles and addressables for some ideas there.


The next bit is just math. If you try to save a 724x1044 image at "Max size 1024", then that height has to change, since 1044 is greater than 1024.

So, following your instructions, Unity scales down the image proportionately, so the height is 1024 (the max allowed), and the width keeps the original 181:261 ratio of the original as best it can. 1024 * 724/1044 = 710.130... which rounds to 710, so you get an image that's 710x1024.

1024 divides evenly by 4, but 710 does not (it's 2 * 355 - no more prime factors of 2 left). So the error message is accurately telling you that it cannot compress the image using ETC2 at the size you've specified.

To fix this, try manually scaling your image (or cropping if necessary) to a desired size that fits the multiple-of-4 criterion. Adding two single-pixel-wide columns of padding or slightly stretching the aspect ratio to 712x1024 would be enough.

If this image is used as a sprite or UI image, then you may also be able to store it in a larger 2048x2048 image and use the extra space to store other sprites - something called a Sprite Atlas. Then each image inside that meta-image is free to have whatever strange dimensions it wants, as long as it doesn't overlap with its neighbours. Unity has features to automatically pack your assets together into atlases, which can also speed up drawing by reducing state switching between content that's drawn back-to-back.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .