(This is a repeat of a post from a couple of years ago. I wanted to clean it up a bit.)
I have a small variation of the DXT1 texture compression algorithm which I’d like to share.
It has the same compression ratio as the original, but improves the quality of low intensity colours. In the best case colours are represented with the equivalent of 24 bit precision. In the worst case colours have 15 bit (555) precision, rather than 16 bit (565) with regular DXT1.
I think this is an acceptable trade-off.
Here’s a side by side comparison. The left image is regular DXT1, the right is the variation. The difference is most obvious in the shadowed areas.
The Wikipedia page explains the DXT1 algorithm in more depth. https://en.wikipedia.org/wiki/S3_Texture_Compression
But here’s a quick summary:
Images are stored in 16 pixel blocks (e.g. 4×4 neighbouring pixels). Each block stores 2 16 bit base colours, and a 2 bit linear interpolation value for each pixel.
Thus a block requires 16 + 16 + 16 x 2 = 64 bits to store, or 4 bits per pixel.
In this variation of the DXT1 algorithm the base colours are 15 bit colours, rather than 16.
The remaining 2 bits are used to store a “bit shift” value between 0 and 3. This bit shift is applied to all 3 components of both the base colours.
The base colours can be unpacked into a 24 bit colour by:
- Copying each component into the top 5 bits of the 8 bit destination byte.
- Right shifting by the “bit shift” value
Red Green Blue "Bit shift"=3 10101 01010 11100 | | | Unpack v v v 10101000 01010000 11100000 ==> ==> ==> Right shift "Bit shift" 00010101 00001010 00011100
This represents the best case scenario of the algorithm, where all components of both colours are intensity 31 (out of 255) or lower. The base colours are expressed as accurately as if they had been stored as 24 bit colours originally.
If they had been stored as two 16 bit (565) colours, they would have unpacked as:
Red Green Blue 00010??? 000010?? 00011???
The worst case scenario is when any component of either base colour is intensity 128 (out of 255) or greater. In this case the “bit shift” must be set to 0, meaning the base colours are simply interpreted as 15 bit colours, 1 bit less precision than standard DXT1.
In my experience the loss of precision is hardly noticeable, as it either corresponds to two high intensity colours or an area of high intensity/low intensity contrast. The eye is less sensitive to subtle intensity differences in brighter colours. And errors in high contrast areas cause less obvious artifacts than in low contrast areas, such as gentle colour gradients.