Skip to main content
GameDev.net gamedev.net
🔒 Locked

Compressed texture formats (DXT1 DXT3 DXT5 etc)

Started by Hyunkel Sep 12, 2010 at 7:37 PM 8 replies 33.4k views
Original Post
Hyunkel
Hyunkel
I've been wondering about this for some time.

As I understand (please correct me if I'm wrong), DXT compressed textures are compressed (lossy) in a way so they do not have to be decompressed before being send to gpu memory.

In other words, if I have 4mb of raw image data, I will end up with 1mb of data after DXT5 compression and use up 1mb of graphics memory instead of 4mb.
The performance impact of using DXT compression is near zero (in fact I've read it may be beneficial since it reduces the graphics card's memory bandwidth load).

Until now I've used DXT5 for all textures except normal maps (I do not use any compression on them), because those react horribly to DXT compression.

However, I still don't feel entirely satisfied with the way I handle things right now.
I know that Directx10 supports all kinds of texture formats with less than 4 channels.
For example, I use specular maps or alpha maps on some occasions, both of which only use a single 'color' channel.
Is there a way to achieve DXT compression for single or dual channel textures? It seems like such a waste to use 4 channels for those.

I've also been wondering what the recommended tool is to compress textures?
Up until now I've used the nvidia photoshop plugin, and let's face it, that's not exactly handy.
I'd prefer something that I can integrate into my engine.
It also seems like the photoshop plugin is missing quite a few newer formats which were introduced with Directx10?

Cheers,
Hyu
Lutz
Lutz
Quote:
Until now I've used DXT5 for all textures except normal maps (I do not use any compression on them), because those react horribly to DXT compression.

Compressed normal maps look pretty good if you do it right. Use a DXT5 texture and put the x-component of the normal map into the alpha channel and zero out r and b. In the shader, you reconstruct the z-component by
float3 n = tex2D(normalMap, texCoord).agg;n.z = sqrt(1 - saturate(n.x*n.x+n.y*n.y));
Note that this only works for tangent-space normal maps (unless you encode the sign of n.z somewhere).

Quote:
For example, I use specular maps or alpha maps on some occasions, both of which only use a single 'color' channel. Is there a way to achieve DXT compression for single or dual channel textures? It seems like such a waste to use 4 channels for those.

In DX9 there is none, not sure about DX10. What is usually done is 1-channel textures are combined into a 3- or 4-channel texture and then compressed. In your cause, you should try putting the spec into the alpha-channel and alpha into the green channel. You do this to minimize artifacts.

A general rule-of-thumb for DXT5: Alpha has least artifacts, then green, then red and blue. This is because of the way the compression works. Artifacts are very visible on spec maps, so you should put them into the alpha channel.

Quote:
I've also been wondering what the recommended tool is to compress textures?
Up until now I've used the nvidia photoshop plugin, and let's face it, that's not exactly handy.
I'd prefer something that I can integrate into my engine.
It also seems like the photoshop plugin is missing quite a few newer formats which were introduced with Directx10?

Not sure about DX10, but the plugin is based on nvdxt.exe, which is a program you can call from the shell and pass in tons of arguments to get what you want. You can download it from the nvidia site.
If you want to integrate DXT compression code directly, I can recomment squish. Very easy to use and the results are pretty good, though we found better techniques for cartoony textures.
MJP
MJP
BC4 (previously known as ATI1N) only has a single normalized channel, either signed or unsigned. BC5 is similar, except with two channels. BC5 is great for normal maps, if you store XY and reconstruct Z.

For texture processing check out the Nvidia texture tools. They handle BC4 and BC5.
Adam_42
Adam_42
One thing to note is that for standard textures which have no alpha channel you want to use DXT1 and not DXT5. It's half the size of DXT5 because it doesn't store the alpha channel.
Hyunkel
Hyunkel
Thanks for all the replies!
I suppose I'll use nvcompress.exe from the nvidia texture tools and just make my program pass arguments to it.
I'll look into BC4 and BC5, sounds exactly like what I want, it seems the photoshop plugin was missing those.


Quote:
Original post by Adam_42
One thing to note is that for standard textures which have no alpha channel you want to use DXT1 and not DXT5. It's half the size of DXT5 because it doesn't store the alpha channel.


I thought DXT5 had better quality then DXT1, even if I don't use an alpha channel?
None of my textures use an alpha channel right now, so this would make quite a difference for me.

Cheers,
Hyu
Adam_42
Adam_42
Quote:
Original post by Hyunkel
I thought DXT5 had better quality then DXT1, even if I don't use an alpha channel?
None of my textures use an alpha channel right now, so this would make quite a difference for me.


The quality of DXT1 should be no worse than DXT5 for textures with no alpha channel. For each 4x4 pixel block DXT5 stores the 8 bytes of DXT1 data, followed by 8 bytes of alpha channel data. DXT1 can be slightly better because it can get different colours in a block by swapping the two colours it interpolates between. See http://en.wikipedia.org/wiki/S3_Texture_Compression for more details of the data format.
Hyunkel
Hyunkel
This is quite interesting, I'll switch to DXT1 compression then.
Thanks for pointing this out! :)

Cheers,
Hyu
Hyunkel
Hyunkel
I want to thank everyone again for helping me out.
I managed to reduce my gpu memory usage for textures from 80 down to only 30mb!

A few things I want to point out if anyone ever decides to use the same combination of tools:
- nvcompress.exe defines BC4 and BC5 with the ATI codes, DirectX10 refuses to read those.
This can be remedied by replacing the ATI codes at offset 0x00000054 in the .dds file, just overwrite it with BC4U or BC5U respectively
- When using BC4 compression with nvcompress.exe, the tool assumes that you want to create an alpha map, so it will read only the alpha channel from the source texture. If you use a grayscale source image, chances are you end up with an alpha value of 1.0 all across the texture.

Cheers,
Hyu
n00body
n00body
@Lutz:
I just thought I'd mention a little modification to your normal-recovery code:
n.z = sqrt(1 - saturate(n.x*n.x+n.y*n.y));// ton.z = sqrt(1 - saturate(dot(n.xy, n.xy)));

This will shaves off 2 instructions, since it eliminates the MADD & MUL, as well as becoming a DP2_SAT instruction.

@Hyunkel:
Compression tools:
AMD's "The Compressonator" tool does a pretty good job offering lots of options for generating various flavors of DXTC data.

Specular:
I'd say you'd be better off putting your specular intensity in the rgb portion of a DXT1/5 texture. As long as you treat the data like a monochrome specular color map in gamma-space, those channels will provide more than sufficient precision. Besides, it will also open up the possibility of using specular color instead of just using intensity.

Efficiency vs Storage cost:
Truth be told, not much really "needs" the precision of the DXT5 alpha channel save for alpha & baked AO. Most data will quite happily fit into the color portion, so you can just use DXT1 textures instead.

Also, don't be so quick to merge multiple textures into one by using DXT5 and shoving them into the alpha channel. While it may save on texture reads, it can be a waste of storage space. Namely, data like specular color, specular power, emissive, baked AO, etc can typically be stored at lower resolution than albedo/normals. So if you split these between multiple textures, you can reduce resolution for maps that don't lose much quality at a lower-frequency.

DXT1 & normals:
Believe it or not, this isn't as bad as you might think. Obviously, the visual quality is lower than when you use BC5/swizzled DXT5. However, as texture resolutions keep going up, the loss of quality becomes less noticeable versus the cost of storage being cut in half for all normal maps. Plus, if you use a detail texture system, you can use low-resolution uncompressed tileable normal textures to help smooth out the artifacts of larger compressed normal textures.

All Unreal Engine 3 games use this method of storing normal maps, so you can get an idea of how it looks from those shipping titles.

@All:
Hope that helps.

[Hardware:] Falcon Northwest Tiki, Windows 7, Nvidia Geforce GTX 970 [Websites:] Development Blog |
Hyunkel
Hyunkel
Thanks, this certainly does help.

The compressonator / Ati's compression library is quite nice. I'd have to write a C# wrapper for it though (I want to use it in my application), and I have never done such a thing before.
The Nvidia compression tools get the job done, and I don't mind changing a few bytes of the file at load time.

I'd certainly use DXT1 for my specular maps, but I set up my deferred renderer to only support monochrome specular highlights, which is why I was searching for a texture format that supports single channel data.

Right now I use:
- Diffuse/Albedo map -> DXT1 / BC1
- Normal map -> BC5
- Specular map -> BC4
- Alpha/Mask map -> BC4

In my current scene, this successfully brings down the memory usage from 164mb to 27mb, which I find quite impressive.
I can also use a different resolution for every map if needed.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.