We’re adding support for compressed textures to Cesium 1.31 via the DXTn/BCn, ECT1, and PVRTC WebGL extensions. Textures compressed to these formats stay compressed in GPU memory and are decompressed in parallel in hardware on the fly when sampling the texture. The compression algorithms compress at a fixed rate that can be decompressed quickly on random access of the texture. For transmission over the web, these textures can be compressed further with a lossless compression algorithm, like gzip. The transmitted texture size is comparable to the size of an image compressed to the JPEG format.

GPU compressed texture formats are lossy, meaning that texture details are lost when compressed. There is a trade-off between texture compression time and texture quality; longer compression times improve the quality of the compressed textures. The crunch compressed textures have a smaller transmission size but have an increased compression time and a small increase to load time due to the transcoding to DXTn/BCn at runtime.

There is not one format that is universally supported by all devices. DXTn/BCn is supported by most desktops, ETC1 is supported on most Android devices and some desktops, and PVRTC is supported by most iOS devices. For an application to utilize texture compression, it must test for what formats are supported and request the appropriate texture. An application that needs to support as many devices as possible and use texture compression will need to compress each texture to each of the formats. If there is no texture compression support in the device, either the uncompressed texture or DXTn/BCn can be used. The DXTn/BCn texture can be transcoded to RGB565 on load.

The gltf-pipeline project has been updated to include texture compression options (see the various --texcomp.* options) using Cesium- and 3D Tiles-specific extras properties that reference ktx files. We’ll explore some of the compression formats and compare the compressed output given different quality values. The original image is a typical satellite image or 3D Tile texture. It is a 1024x1024 RGB image. Not all of the compression formats support an alpha channel. Luckily, most satellite imagery and 3D Tile textures will not require one. The transmitted size is 476KB (JPEG), but the in memory decompressed size is 3MB. JPEG compression is also a lossy compression format.

Original JPEG Image Difference (in purple)

The image differences were generated with Resemble.js. Clicking an image will open the full 1024x1024 image in a new browser tab.

In the tables below, CRN is the format output by crunch. It is a highly compressed, lossy format that quickly transcodes to DXT1 or DXT5. KTX is a container format for storing textures. KTX + gzip is the size of the KTX file after compressing with gzip using the standard settings. PSNR is the peak signal-to-noise ratio. A higher PSNR means the image reconstructed from the compressed image is closer to the source image. The PSNR should only be used to compare an image compressed to the same format. Therefore, one should not compare the PSNR of the images compressed with ETC1 with the PSNR of the images compressed with PVRTC.

All compression times were recorded when running on a 3.20 GHz Intel Xeon E5-1650 CPU and Windows 10. Compressing multiple textures in parallel will, of course, improve compression times for an entire scene.

gltf-pipeline uses crunch to compress to CRN and DXTn/BCn, etc2comp to compress to ETC1, and PVRTexTool to compress to PVRTC. gltf-pipeline will compress textures with commands similar to below. The quality set for each compressed texture is the number above each image.

node ./bin/gltf-pipeline.js -i /path/to/gltf -o /path/to/output --texcomp.quality 9 --texcomp.format crunch-dxt1

node ./bin/gltf-pipeline.js -i /path/to/gltf -o /path/to/output --texcomp.quality 1 --texcomp.format etc1

DXT1

The DXT1 compressed texture is 513KB, which is a sixth of the size of the uncompressed image when in GPU memory. DXT1 does not support an alpha channel.

1 2 3 4 5
CRN 99KB 117KB 131KB 143KB 153KB
KTX + gzip 159KB 193KB 218KB 240KB 258KB
PSNR 26.140 27.272 27.924 28.487 28.989
Compression Time (s) 3.127 3.506 3.413 4.076 4.581
DXT1 6 7 8 9 10
CRN 164KB 174KB 183KB 192KB 200KB
KTX + gzip 273KB 286KB 297KB 305KB 311KB
PSNR 29.463 29.887 30.315 30.708 31.085
Compression Time (s) 5.482 6.335 7.473 9.286 11.528

DXT5

DXT5 does not compress as well as DXT1, but can also store an alpha channel. The DXT5 compressed texture size is 1025KB, about a third of the size of the uncompressed image. There is also an option to use DXT3. DXT3 uses the same compression for the RGB data of texture but uses less bits to store the alpha channel. DXT5 should be preferred for gradient alpha whereas DXT3 should be preferred for sharp alpha changes. DXT3 is also an unsupported crunch format.

1 2 3 4 5
CRN 122KB 139KB 151KB 162KB 171KB
KTX + gzip 222KB 261KB 285KB 302KB 315KB
PSNR 26.951 27.856 28.449 28.948 29.343
Compression Time (s) 4.858 5.415 5.451 6.427 7.355
6 7 8 9 10
CRN 179KB 186KB 194KB 200KB 207KB
KTX + gzip 323KB 330KB 336KB 341KB 346KB
PSNR 29.745 30.091 30.420 30.737 31.018
Compression Time (s) 7.565 8.933 9.338 10.619 13.153

ETC1

ETC1 has a similar compression ratio to DXT1. The ETC1 compressed texture size is 513KB. ETC1 does not support an alpha channel.

1 2 3 4 5
KTX + gzip 407KB 408KB 409KB 409KB 411KB
PSNR 38.7594 38.9216 38.9216 39.0379 39.1980
Compression Time (s) 1.328 1.926 2.481 3.116 5.372
6 7 8 9 10
KTX + gzip 413KB 417KB 419KB 421KB 425KB
PSNR 39.2808 39.3893 39.4450 39.4791 39.5111
Compression Time (s) 8.221 16.419 29.390 43.279 60.042

PVRTC 2bpp

The PVRTC 2bpp compressed texture size is 257KB.

1,2 3,4 5,6 7,8 9,10
KTX + gzip 209KB 210KB 218KB 219KB 219KB
PSNR 40.222 40.294 41.119 41.174 41.188
Compression Time (s) 0.908954 1.1497999 9.3760064 18.0452953 34.1600244

PVRTC 4bpp

The PVRTC 4bpp compressed texture size is 513KB.

1,2 3,4 5,6 7,8 9,10
KTX + gzip 357KB 383KB 418KB 422KB 423KB
PSNR 40.515 41.300 42.348 42.423 42.449
Compression Time (s) 1.1524799 1.4298776 3.8276361 5.9442022 9.9473701

Recommendations

For desktops, you will need to use a DXTn/BCn format. If you are going to use crunch, I suggest DXT1 and setting the quality of textures at the root of the tileset to 1 and increase the quality to 10 as you reach the leaf nodes. As you can see in the table above, the quality of crunched textures quickly degrades. The benefit of crunch is the quick load times. The largest crunched texture was still less than half the size of the same texture in the JPEG format.

If you do not want to use crunch, I would suggest DXT1 with the quality set to 1 for all textures. The DXTn/BCn textures that were not crunched are not shown above. The image diffs are very similar to those in the ETC1 table. The lowest quality DXT1 compressed texture has better quality than the highest quality DXT1 crunched texture and is a little faster than the lowest quality crunched texture.

For Android, You will need to use ETC1. I suggest setting the quality to 1. The compression time drastically increases for very little quality gain.

For iOS, you will need to use PVRTC. I suggest using PVRTC 4bpp and setting the quality between 3 and 6. If your app is memory constrained and you can tolerate more error in the compressed texture, you can switch to using PVRTC 2bpp and setting the quality to be between 1 and 4.