DDS是DirectDraw Surface的缩写,实际上,它是DirectX纹理压缩(DirectX Texture Compression,简称DXTC)的产物。DDS文件的纹理压缩有很多方式,除了常见的DXTn外,也支持Mipmap, Cubemap, 和volume maps等更多的格式,但后者不会在这里介绍。
DDS文件数据包含一个固定128字节的DDS文件头(不包含DXT10,DXT10还需要20字节的扩展头,这里不讨论)和图像数据。DDS文件头的格式如下:
dwMagic |
4字节 1双字 |
DDS文件标识,固定为“DDS ”(有个空格), 即0x20534444。 |
dwSize |
4字节 1双字 |
DDS文件头大小(不包括标识的4字节),因此固定为124,即0x7C。 |
dwFlags |
4字节 1双字 |
DDS文件标志位。有8个位有效(标☆的表示DNF中DDS文件所需要的标志位): 0x00000001:☆每个DDS文件都必须有。 0x00000002:☆每个DDS文件都必须有。 0x00000004:☆每个DDS文件都必须有。 0x00000008:若纹理数据是非压缩,该位为1。 0x00001000:☆每个DDS文件都必须有。 0x00020000:若为Mipmap,该位为1。 0x00080000:☆若纹理数据是压缩的,该位为1。 0x00800000:若纹理具有深度数据(适用于volume maps),该位为1。 DNF里所有DDS文件的标志位均为0x0081007。 |
dwHeight |
4字节 1双字 |
图像高度(以像素为单位,一般是4的倍数) |
dwWidth |
4字节 1双字 |
图像宽度(以像素为单位,一般是4的倍数) |
dwPitchOrLinearSize |
4字节 1双字 |
对非压缩数据表示一行像素所需要的字节数; 对压缩数据则表示整个图像数据的字节数。 DNF里为后者。 |
dwDepth |
4字节 1双字 |
纹理具有深度数据时,表示纹理的深度。DNF里无用,固定为0。 |
dwMipMapCount |
4字节 1双字 |
Mipmap层数,适用于Mipmaps。DNF里无用,固定为0。 |
dwReserved1[11]; |
44字节 11双字 |
官方用作保留位,但DNF里此字段第10个和第11个双字分别为0x5454564E (“NVTT”字符串)和0x20008,并不明白其用途,估计是作为签名或者另 一个标识符。 |
ddspf |
32字节 8双字 |
DDS像素格式,是一个含有8个双字的结构体,将在下文中描述。 |
dwCaps |
4字节 1双字 |
此字段用于指定纹理存储的复杂度,有3个位有效(标☆的表示DNF中DDS 文件所需要的标志位) 0x00000008:复杂纹理(采用Mipmaps或Cubemap)。 0x00001000:☆纹理,每个DDS文件都必须有。 0x00400000:Mipmap格式。 |
dwCaps2 |
4字节 1双字 |
此字段用于指定纹理存储的额外事项,包括Cubemap和Volume map的一些信息。 DNF里无用,固定为0. |
dwCaps3 |
4字节 1双字 |
官方用作保留位,DNF里为0。 |
dwCaps4 |
4字节 1双字 |
官方用作保留位,DNF里为0。 |
dwReserved2 |
4字节 1双字 |
官方用作保留位,DNF里为0。 |
DDS像素格式是个含有8个双字/32个字节的结构体,其含义如下:
dwSize |
4字节 1双字 |
这个结构体的字节数,也就是32(0x20) |
dwFlags |
4字节 1双字 |
DDS图像数据格式。有6个位有效(标☆的表示DNF中DDS文件所需要的标志位): 0x00000001:纹理包含透明通道,非压缩数据适用。 0x00000002:某些旧的DDS文件才用的上。 0x00000004:☆采用压缩数据,格式由FourCC决定。 0x00000040:纹理包含RGB通道,非压缩数据适用。 0x00000200:某些旧的DDS文件才用的上。 0x00020000:某些旧的DDS文件才用的上。 DNF里有所DDS文件该字段均为0x4。 |
dwFourCC |
4字节 1双字 |
当采用压缩数据时此字段才有效,可以是: 0x31545844:字符串DXT1,表示采用DXT1压缩。 0x32545844:字符串DXT2,表示采用DXT2压缩。 0x33545844:字符串DXT3,表示采用DXT3压缩。 0x34545844:字符串DXT4,表示采用DXT4压缩。 0x35545844:字符串DXT5,表示采用DXT5压缩。 DNF采用的是压缩数据,一般是DXT1/3/5。 |
dwRGBBitCount |
4字节 1双字 |
当采用非压缩数据时此字段才有效,表示一个像素的RGB(估计也有透明通道) 所包含的位数。DNF里无用,为0。 |
dwRBitMask |
4字节 1双字 |
当采用非压缩数据时此字段才有效,表示R通道掩码。DNF里无用,为0。 |
dwGBitMask |
4字节 1双字 |
当采用非压缩数据时此字段才有效,表示G通道掩码。DNF里无用,为0。 |
dwBBitMask |
4字节 1双字 |
当采用非压缩数据时此字段才有效,表示B通道掩码。DNF里无用,为0。 |
dwABitMask |
4字节 1双字 |
当采用非压缩数据时此字段才有效,表示透明通道掩码。DNF里无用,为0。 |
在DDS图像中,一般以4×4像素作为一个“块”为单位来进行压缩处理的。不同的DXT格式对块的压缩的方式也不同,压缩效果也不同。
注:DXTn中均以2字节表示一个颜色,采用RGB565的存储方式,即如下图所示:
DXT1采用8字节(2个双字)来表示一个块,因此针对ARGB8888像素的压缩比是8:1。其原理是取这个块中两个颜色点(最大值和最小值)为关键色,然后通过线性插值的方式算出其他中间色,然后通过插值索引的方式确定每个像素使用的是哪种颜色。
DXT1中,前两个字节表示颜色1(color1),第三第四个字节表示颜色2(color2),剩下4个字节表示16个像素的所有的插值索引,也就是说每个像素有2位作为插值索引,因此每个像素的插值索引的取值为0到3(如下图所示)。
当关键色color1>color2时,表示该块不采用透明度存储,因此将color1到color2的色域分为3等分,取中间两点为color3和color4,通过每个像素的插值索引决定是哪个color。当关键色color1 由此可见,DXT1支持透明像素存储,但不支持半透明像素存储,对有半透明像素的纹理,应采用DXT2以上的版本。 DXT2和DXT3采用16字节(4个双字)来表示一个块,针对ARGB8888像素的压缩比是4:1。DXT2和DXT3分为两个部分,低8字节是透明度通道部分,高8字节是颜色部分。颜色部分的数据存储方式与DXT1一致,但DXT2的颜色部分是已经基于原色进行过透明度处理后的颜色,这一点是DXT2与DXT3的唯一不同之处。 DXT2和DXT3中,低8字节直接存储16个像素的透明度通道,因此每个像素的透明度通道是4位,范围是0到255。由于透明度已经有数据进行存储,因此在高8字节的颜色部分中,不再通过color1和color2的比较确定该块是否使用透明度存储,而是一致地使用DXT1中不采用透明度存储时的算法。 由此可见,DXT2和DXT3支持了半透明像素的存储,但是透明度范围锁定在全域,且只有16个值可以选,对精细的纹理,还是不足以满足要求,而应采用版本更高的DXT4或DXT5。 DXT4和DXT5跟DXT2和DXT3一样,采用16字节(4个双字)来表示一个块,针对ARGB8888像素的压缩比是4:1。也是分为两部分,高8字节的颜色部分跟DXT2和DXT3一样,但是低8字节的透明度通道部分,则采用跟颜色部分类似的线性插值算法,即取两个像素的透明度作为关键透明度alpha1和alpha2,通过线性插值方式算出其他中间透明度,然后通过透明度插值索引方式确定每个像素的透明度。 DXT4和DXT5中,第一字节表示第一个关键透明度alpha1,第二字节表示第二个关键透明度alpha2,其他6字节用于存储16个像素透明度插值索引,因此每个像素的透明度插值索引为3位,即0-7。 当alpha1>alpha2时,将这段区间分为7等分,中间的6个点分别为alpha3、alpha4、alpha5、alpha6、alpha7、alpha8,然后通过透明度插值索引来确定该像素的透明度是哪个alpha值;当alpha1 DXT4和DXT5由于alpha值的范围不平均分布在0-255之间,而是在某些特定的值之间(或者加上0和255),因此可以更好的实现透明度的平滑,适合存储更精细的纹理。 在DNF中,有些具有实前景的技能特效(比如冰霜钻孔车)一般都使用DXT1进行存储,而带有半透明的特效(比如杰克降临后面的火焰,还有某些实体的外发光等)一般使用DXT5进行存储。