There are special formats of textures which are optimized for access by graphics processors. They differ from formats whose primary mission is to hold / transmit image data for use on a CPU. Examples of image formats are .JPG & .PNG. Formats catering to GPUs may not be ones you are likely to have heard of. The file extensions for some of them are also not well established.
Unlike image file formats, the data of compressed textures is passed to the graphics hardware in its compressed form. A .JPG can be very small on disk, but gets expanded by the CPU on its way to the GPU. Retaining its compressed form is what gives these formats their advantages. They are:
There is more than one format for compressed textures. Due to the low level implementation for them in hardware, support for a given format cannot be added like a software driver update. Support is manufactured right into the circuitry. This is less of a problem when building an iOS, Android, or DirectX targeted application. For a BJS scene which should ideally be able to run on any device / browser, this is a big problem. Having separate HTML pages for different devices is not really an acceptable solution.
Starting with Babylon.js v3.0, the compressed texture formats supported by a browser / device can be detected. This is done when
var engine = new BABLYON.Engine(...); is encountered. So now your engine instance knows which compressed formats could be used here. That does not solve that different devices will report different results though.
You can also use this playground -
There is no getting around the fact that you need to provide multiple versions of each texture in different formats(more on that later). The only way of doing that involves having different files for each of the variants obviously, but the naming structure must be formalized in order to programmatically substitute for the image format file described in a .babylon file. The image format file of each texture still needs to be on the server as well, in cases when it needs to be used.
Now would be a good time to add the aside that due to the fact that this data is not directly used by CPU's and GPU's do not actually "read" files, there may or may not be an actual native file format for a given compression format. Even for those that do have an associated file format, writing load code for each separately would be tedious and require support.
Enter compressed texture container files, which can handle multiple or even all texture types. There are also a few container file formats as well (.DDS, .PVR, & .KTX). Container files can also have all the mipmaps of a texture inside them. BJS, implements this feature using KTX container files. KTX is specifically designed for OpenGL, and forces all the arcane code to handle any format OpenGL supports onto the file encoder / generator, even future formats without us doing anything other than adding extension detection, like ASTC.
Here is a chart of all the current formats possible for WebGL, listed in the order chosen when hardware supports multiple formats (tie breakers):
|ASTC||*-astc.ktx||Newly approved for WebGL, most powerful, cross-platform. Implemented in many newer processors, but not exposed by any browsers yet.||Always|
|DXT||*-dxt.ktx||Direct X, available primarily on Desktop Operating Systems.||Yes|
|PVRTC||*-pvrtc.ktx||Proprietary. Power VR chips (includes all Apple iOS processors). Must be square.||Yes|
|ETC2||*-etc2.ktx||ETC1 + alpha capable. Required by WebGL 2 (or at least OpenGL ES 3, on which WebGL 2 is based).||Yes|
|ATC||*-atc.ktx||Format originating at AMD. No encoder which supports .KTX found at this time.||Yes|
|ETC1||*etc1.ktx||Wide support among older mobile devices. Need to fall back to images for .PNG files.||No|
Once your engine instance is established, you need to indicate the compressed formats that you have put on the server from which it can pick from. This should probably be done very early, as follows:
// order & case do not matter var available = ['-astc.ktx', '-dxt.ktx', '-pvrtc.ktx', '-etc2.ktx', '-etc1.ktx']; var formatUsed = engine.setTextureFormatToUse(available);
The are multiple encoder programs for .KTX files (see .KTX link above). Most also provide for batch processing, since many formats are very CPU intense. PVRTexTool has been narrowed down for providing additional support. It has a lot going for it, including both a GUI & command line interface for Windows, OSX, and Linux. It is also the only encoder which does PVRTC format, which is needed on iOS.
If you are going to do the encoding on your own in the PVRTexTool GUI tool, there are a few things to keep in mind:
There are 2 batch scripts in the BJS repo. They both require that PVRTexToolCLI.exe, be put on the execution path just as the ASTC drop-in was. Doing both at the same time, and locating these 2 .BAT files in the same place seems like a good thing to do.
This script goes through the current directory, and writes a
ktx-batch.bat file there. When you then call
ktx-batch.bat, it will make an ASTC, DXT, PVRTC, ETC2, and ETC1 file for each .JPG and .PNG in the directory. Note that a .PNG extension is an indicator to use an alpha capable sub-type. ETC1 does not support alpha, so the .PNG will be used as a fall back, if ETC1 ends up being chosen.
There is a single argument which indicates the quality of the texture. Specify D for developer level, Q for production quality. Tip: unless you are testing if this fixes hanging issues on mobile devices, you could just delay enabling this till all your textures get finalized. Also, do not rely on the results you get from using D on a desktop. DXT does not really have variable quality.
This script will create the 5 variations of a image file. It can run for a very long time for Q setting. The ASTC type will use 100% of all your cores, so your system can be pretty unusable. Good to kick it off at the end of day. Also, due to running time, it will skip any files already existing. To re-do files, delete the existing versions first.
To recap (in a command shell):
cd my-directory-with-images make-ktx-batch Q ktx-batch