- Home /
Can you load dds textures during runtime?
My game lets users create custom content so loading a large number of textures quickly is important. I was wondering if it was possible to load dds files since they already have dxt info stored in them and it would be much faster than loading a jpg or png.
Answer by jeff-smith · May 14, 2014 at 03:13 PM
I've found a lot of good help on the Unity forums, so it is my turn to provide an answer.
DDS (DirectDraw Surface) files can be loaded in Unity at runtime using the Texture2D LoadRawTextureData() method. On our project at NOAA, we are loading hundreds of 4000 x 2000 jpg images and the time required to load each texture and compress it was roughly 600 ms (milliseconds). Too slow!
I found that the time required to load the DDS version of the same image (with DXT1 compression) is roughly 3 ms! Amazingly fast. So how can you get your images into DDS format, and how can you load them in Unity?
To save your images into DDS format, you can use Photoshop with the Nvidia texture tools plugin (https://developer.nvidia.com/nvidia-texture-tools-adobe-photoshop), or you can use a free tool like GIMP (with its DDS plugin--https://code.google.com/p/gimp-dds/). I used GIMP 2.8 with the plugin. Load your jpg/png image(s) into one of these tools, and then export it as a DDS file. Choose DXT1 compression if your image doesn't have an alpha channel (e.g., JPG images) or DXT5 compression if your images do have alpha (e.g., PNG).
To load your DDS file in Unity, you'll need to read the DDS header which is described in detail here: http://doc.51windows.net/Directx9_SDK/?url=/directx9_sdk/graphics/reference/DDSFileReference/ddsfileformat.htm
Basically, a DDS file has a 128 byte header which contains some useful information like the width and height of your image. You need to exclude the header bytes, however, when you pass the bytes to the LoadRawTextureData method (which was added in Unity 4.3 but sadly has not yet been documented). Here's my code for loading a DDS file into a Texture2D within a class named TextureLoader:
public static Texture2D LoadTextureDXT(byte[] ddsBytes, TextureFormat textureFormat)
{
if (textureFormat != TextureFormat.DXT1 && textureFormat != TextureFormat.DXT5)
throw new Exception("Invalid TextureFormat. Only DXT1 and DXT5 formats are supported by this method.");
byte ddsSizeCheck = ddsBytes[4];
if (ddsSizeCheck != 124)
throw new Exception("Invalid DDS DXTn texture. Unable to read"); //this header byte should be 124 for DDS image files
int height = ddsBytes[13] * 256 + ddsBytes[12];
int width = ddsBytes[17] * 256 + ddsBytes[16];
int DDS_HEADER_SIZE = 128;
byte[] dxtBytes = new byte[ddsBytes.Length - DDS_HEADER_SIZE];
Buffer.BlockCopy(ddsBytes, DDS_HEADER_SIZE, dxtBytes, 0, ddsBytes.Length - DDS_HEADER_SIZE);
Texture2D texture = new Texture2D(width, height, textureFormat, false);
texture.LoadRawTextureData(dxtBytes);
texture.Apply();
return (texture);
}
So you just need to read the bytes from a DDS file and then pass them to this C# method. Here's some simple code to do that:
byte[] bytes = System.IO.File.ReadAllBytes(ddsFilePath);
Texture2D myTexture = TextureLoader.LoadTextureDXT(bytes, TextureFormat.DXT1);
You should see 100x speedup in loading images into Texture2Ds. I hope this post helps someone.
I have been attempting to use your method, but keep getting this error. Did you run into this at all?
UnityException: LoadRawTextureData: not enough data provided (will result in overread).
Utility.LoadTexture (System.Byte[] ddsBytes) (at Assets/Scripts/Utilities/Utility.cs:134)
The file is definitely a DDS file. It loads the header and accurately obtains the width and height.
I found out my above error was caused by trying to LoadRawTextureData
into a Texture that I had mipmaps set to true. $$anonymous$$y DDS file had no mipmaps, so it was unable to deal with that.
Setting mipmaps to false when initializing my texture fixed the problem.
That's a subtle error - glad you figured it out!
The docs for LoadRawTextureData are nonexistent, so a lot of what we've figured out is by trial and error. I've been wary to try anything fancy, like loading into a cubemap or a texture with mipmaps. Good to know that it appears to support mipmaps.
It would be really nice for debugging to have the reverse method, e.g. ReadRawTextureData, which would return a byte stream so we know what Unity is expecting..
Glad you figured that out, Tylo. You'll also see that error message if your texture.format is mismatched. For example if texture.format=TextureFormat.ARGB32 (PNG) and yet your source DDS file is 24 bit (JPG with no alpha).
Answer by tylo · May 22, 2018 at 02:11 AM
In case anyone else stumbles on this, you can also detect what compression algorithm the DDS file is using by checking bytes in the header file.
ddsBytes[84], ddsBytes[85], ddsBytes[86], ddsBytes[87]
Each one of these bytes contains the ASCII values of a 4 letter code.
DXT1 and DXT5 are the most relevant in the case of Unity.
Answer by phoenixrising · Oct 23, 2018 at 05:51 PM
You can also use Unity's crunch to process on the command line
Your answer
![](https://koobas.hobune.stream/wayback/20220613115941im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Apply transparent texture to plain at runtime 1 Answer
Runtime Normal Map Import Issues 0 Answers
Assigning UV Map to model at runtime 0 Answers
Loading texture file from png/jpg file on disk 5 Answers
Reverse of Texture.EncodeToEXR in unity? 0 Answers