HTML and CSS Reference
This is problematic for real-time 3D applications, which typically strive to render at 60 frames per second. This
means that each frame must complete within about 16ms. If a single texture takes 18ms to upload, it means that you've
completely missed one frame update and have eaten into the next one just to put one texture on your graphics card!
Even an upload time of 11 or 12ms is bad, however, because it only leave 4ms to 5ms to render the rest of your scene.
That's plenty for a simple scene like our gallery, but it's not nearly enough for even moderately complex 3D scenes.
The solution is to use compressed textures , a staple of 3D games for many years. Unlike compressed image formats
like JPEG or PNG, which examine the entire file and then compress based on large features and common patterns,
compressed textures use fixed-rate compression schemes that operate on small blocks of pixels. The GPU is
optimized to decompress those blocks on the fly during rendering. This allows the texture to remain compressed in
memory, taking up a fraction of the memory that it otherwise would have. The compression is lossy, which typically
makes compressed textures inappropriate for data textures like normal maps, but they usually work well for diffuse
information (much like JPEGs).
There are multiple compressed texture formats, each with different compression characteristics and hardware
support. One of the most common ones is S3 Texture Compression (S3TC), which is more commonly known as DXT
due to its inclusion in Direct X from version 6 forward. At this point, DXT compressed textures are supported by
almost any PC you can purchase, and are also available on many mobile devices.
Using compressed textures on phones or tablets is still somewhat tricky because each device tends to have a
preferred compression format that is usually owned by the device's GPU manufacturer. For example, all iOS devices
support Imagination's PVRTC format, but none of them support DXT. Since iOS devices don't support WebGL as of
this writing, however, and DXT is one of the more common formats, we'll focus on it for the purposes of this article.
Just be aware that if you're targeting mobile, you'll first need to check for support and have fallback textures encoded
in a different format to ensure that your app runs correctly.
There are five DXT variants, each with different properties, of which WebGL supports three via the
WEBGL_compressed_texture_s3tc extension ( http://www.khronos.org/registry/webgl/extensions/
• DXT1 is the smallest variant, sporting a 6:1 compression ratio. (For every 6 bytes of
uncompressed data, DXT1 only requires 1 byte.) That shrinks your 1024×1024 images from
3MB to 512KB! The downside is that DXT1 doesn't support alpha channels but, depending on
the texture, that may or may not be a problem.
• DXT3 has a compression ratio of 4:1, and it supports 4 bits of alpha data per pixel. This makes
DXT3 best suited for images that have sharp alpha transitions.
• DXT5 also has a 4:1 compression ratio, but it handles smooth alpha transitions better than
Loading DDS Files
DXT compressed textures are often read from DDS files, which is a container format developed by Microsoft. The
format is fairly simple and well documented, consisting of little more than a header followed by the texture data.
Fortunately this isn't very difficult! Let's walk through building a simple DDS parser library. There's a fair bit of code
involved, but taken piece by piece there's nothing too complicated here. I'll refer to this library as dxt_util.js . You
can find the completed version in the source code for this chapter.
First off, you'll need to define some utility functions, so look at Listing 21-1.