DDS 编程指南
Direct3D 实现 DDS 文件格式,用于存储未压缩或压缩 (DXTn) 纹理。 文件格式实现几个略有不同的类型,旨在存储不同类型的数据,并支持单层纹理、带有 mipmap 的纹理、多维数据集贴图、体积贴图和 Direct3D 10/11) 中的 (纹理数组。 本部分介绍 DDS 文件的布局。
有关在 Direct3D 11 中创建纹理的帮助,请参阅 如何:创建纹理。 有关 Direct3D 9 的帮助,请参阅 D3DX (Direct3D 9) 中的纹理支持 。
DDS 文件布局
DDS 文件是包含以下信息的二进制文件:
包含四个字符代码值“DDS ”\(0x20534444\) 的 DWORD(幻数)。
文件中数据的描述。
使用 DDS_HEADER 描述具有标头描述的数据;使用 DDS_PIXELFORMAT 定义像素格式。 请注意,DDS_HEADER 和 DDS_PIXELFORMAT 结构会替换已弃用的 DDSURFACEDESC2、DDSCAPS2 和 DDPIXELFORMAT DirectDraw 7 结构。 DDS_HEADER 是等效于 DDSURFACEDESC2 和 DDSCAPS2 的二进制结构。 DDS_PIXELFORMAT 是等效于 DDPIXELFORMAT 的二进制结构。
DWORD dwMagic; DDS_HEADER header;
如果DDS_PIXELFORMAT dwFlags 设置为 DDPF_FOURCC而 dwFourCC 设置为“DX10”,则会出现额外的 DDS_HEADER_DXT10 结构,以适应无法表示为 RGB 像素格式的纹理数组或 DXGI 格式,例如浮点格式、sRGB 格式等。当 存在DDS_HEADER_DXT10 结构时,整个数据说明将如下所示。
DWORD dwMagic; DDS_HEADER header; DDS_HEADER_DXT10 header10;
指向包含主要图面数据的字节数组的指针。
BYTE bdata[]
指向包含其余图面的字节数组的指针;mipmap 级别、立方体贴图中的面以及体纹理中的深度。 跟随这些链接可获得有关以下内容的 DDS 文件布局的详细信息:纹理、立方体贴图或体纹理。
BYTE bdata2[]
对于广泛的硬件支持,建议使用 DXGI_FORMAT_R8G8B8A8_UNORM、DXGI_FORMAT_R8G8B8A8_UNORM_SRGB、DXGI_FORMAT_R8G8B8A8_SNORM、DXGI_FORMAT_B8G8R8A8_UNORM、DXGI_FORMAT_R16G16_SNORM、DXGI_FORMAT_R8G8_SNORM、DXGI_FORMAT_R8_UNORM、DXGI_FORMAT_BC1_UNORM、DXGI_FORMAT_BC1_UNORM_SRGB、DXGI_FORMAT_BC2_UNORM、DXGI_FORMAT_BC2_UNORM_SRGB、 DXGI_FORMAT_BC3_UNORM或DXGI_FORMAT_BC3_UNORM_SRGB格式。
有关压缩纹理格式的详细信息,请参阅 Direct3D 11 中的纹理块压缩 和 Direct3D 10) (块压缩 。
例如,D3DX 库 (D3DX11.lib) 和其他类似库不可靠或不一致地在 DDS_HEADER 结构的 dwPitchOrLinearSize 成员中提供间距值。 因此,在读取和写入 DDS 文件时,建议使用以下任一方式计算指定格式的音调:
对于块压缩格式,按以下方式计算音高:
max ( 1, ( (width+3) /4) ) * 块大小
对于 DXT1、BC1 和 BC4 格式,块大小为 8 个字节,对于其他块压缩格式,块大小为 16 个字节。
对于R8G8_B8G8、G8R8_G8B8、旧 UYVY 打包格式和旧版 YUY2 打包格式,按以下方式计算音调:
( (width+1) >> 1) * 4
对于其他格式,按以下方式计算音调:
( 宽度 * 每像素位数 + 7 ) / 8
除以 8 进行字节对齐。
注意
计算的音高值并不总是等于运行时提供的音高,在某些情况下,DWORD 对齐,在其他情况下字节对齐。 因此,建议一次复制扫描行,而不是尝试在一个副本中复制整个图像。
DDS 变体
有许多工具可用于创建和使用 DDS 文件,但它们在标头中所需的详细信息上可能会有所不同。 编写器应尽可能完整地填充标头,并且读取者应检查最小值以实现最大的兼容性。 若要验证 DDS 文件,读取器应确保文件长度至少为 128 字节,以适应 magic 值和基本标头,magic 值为 0x20534444 (“DDS”) ,DDS_HEADER大小为 124,标头大小的DDS_PIXELFORMAT为 32。 如果DDS_PIXELFORMAT dwFlags 设置为 DDPF_FOURCC而 dwFourCC 设置为“DX10”,则总文件大小至少为 148 字节。
在使用中的一些常见变体中,像素格式设置为DDPF_FOURCC代码,其中 dwFourCC 设置为 D3DFORMAT 或DXGI_FORMAT枚举值。 无法判断枚举值是 D3DFORMAT 还是DXGI_FORMAT,因此,当基本DDS_PIXELFORMAT无法表示格式时,强烈建议改用“DX10”扩展和DDS_HEADER_DXT10标头来存储 dxgiFormat。
对于存储 RGB 未压缩数据和 DXT1-5 数据的最大兼容性,应首选标准DDS_PIXELFORMAT,因为并非所有 DDS 工具都支持 DX10 扩展。
在 Direct3D 10/11 中使用纹理数组
Direct3D 10/11 中 (DDS_HEADER 和 DDS_HEADER_DXT10) 的新 DDS 结构扩展了 DDS 文件格式,以支持纹理数组,这是 Direct3D 10/11 中的新资源类型。 下面是一些示例代码,演示如何使用新标头访问纹理数组中的不同 mipmap 级别。
DWORD dwMagic;
DDS_HEADER header;
DDS_HEADER_DXT10 header10;
for (int iArrayElement = 0; iArrayElement < header10.arraySize; iArrayElement++)
{
for (int iMipLevel = 0; iMipLevel < header.dwMipMapCount; iMipLevel++)
{
...
}
}
常见的 DDS 文件资源格式和关联的标头内容
资源格式 | dwFlags | dwRGBBitCount | dwRBitMask | dwGBitMask | dwBBitMask | dwABitMask |
---|---|---|---|---|---|---|
DXGI_FORMAT_R8G8B8A8_UNORM D3DFMT_A8B8G8R8 |
DDS_RGBA | 32 | 0xff | 0xff00 | 0xff0000 | 0xff000000 |
DXGI_FORMAT_R16G16_UNORM D3DFMT_G16R16 |
DDS_RGBA | 32 | 0xffff | 0xffff0000 | ||
** DXGI_FORMAT_R10G10B10A2_UNORM D3DFMT_A2B10G10R10 |
DDS_RGBA | 32 | 0x3ff | 0xffc00 | 0x3ff00000 | |
DXGI_FORMAT_R16G16_UNORM D3DFMT_G16R16 |
DDS_RGB | 32 | 0xffff | 0xffff0000 | ||
DXGI_FORMAT_B5G5R5A1_UNORM D3DFMT_A1R5G5B5 |
DDS_RGBA | 16 | 0x7c00 | 0x3e0 | 0x1f | 0x8000 |
DXGI_FORMAT_B5G6R5_UNORM D3FMT_R5G6B5 |
DDS_RGB | 16 | 0xf800 | 0x7e0 | 0x1f | |
DXGI_A8_UNORM D3DFMT_A8 |
DDS_ALPHA | 8 | 0xff | |||
D3DFMT_A8R8G8B8 |
DDS_RGBA | 32 | 0xff0000 | 0xff00 | 0xff | 0xff000000 |
D3DFMT_X8R8G8B8 |
DDS_RGB | 32 | 0xff0000 | 0xff00 | 0xff | |
D3DFMT_X8B8G8R8 |
DDS_RGB | 32 | 0xff | 0xff00 | 0xff0000 | |
** D3DFMT_A2R10G10B10 |
DDS_RGBA | 32 | 0x3ff00000 | 0xffc00 | 0x3ff | 0xc0000000 |
D3DFMT_R8G8B8 |
DDS_RGB | 24 | 0xff0000 | 0xff00 | 0xff | |
D3DFMT_X1R5G5B5 |
DDS_RGB | 16 | 0x7c00 | 0x3e0 | 0x1f | |
D3DFMT_A4R4G4B4 |
DDS_RGBA | 16 | 0xf00 | 0xf0 | 0xf | 0xf000 |
D3DFMT_X4R4G4B4 |
DDS_RGB | 16 | 0xf00 | 0xf0 | 0xf | |
D3DFMT_A8R3G3B2 |
DDS_RGBA | 16 | 0xe0 | 0x1c | 0x3 | 0xff00 |
D3DFMT_A8L8 |
DDS_LUMINANCE | 16 | 0xff | 0xff00 | ||
D3DFMT_L16 |
DDS_LUMINANCE | 16 | 0xffff | |||
D3DFMT_L8 |
DDS_LUMINANCE | 8 | 0xff | |||
D3DFMT_A4L4 |
DDS_LUMINANCE | 8 | 0xf | 0xf0 |
资源格式 | dwFlags | dwFourCC |
---|---|---|
DXGI_FORMAT_BC1_UNORM D3DFMT_DXT1 |
DDS_FOURCC | “DXT1” |
DXGI_FORMAT_BC2_UNORM D3DFMT_DXT3 |
DDS_FOURCC | “DXT3” |
DXGI_FORMAT_BC3_UNORM D3DFMT_DXT5 |
DDS_FOURCC | “DXT5” |
* DXGI_FORMAT_BC4_UNORM |
DDS_FOURCC | “BC4U” |
* DXGI_FORMAT_BC4_SNORM |
DDS_FOURCC | “BC4S” |
* DXGI_FORMAT_BC5_UNORM |
DDS_FOURCC | “ATI2” |
* DXGI_FORMAT_BC5_SNORM |
DDS_FOURCC | “BC5S” |
DXGI_FORMAT_R8G8_B8G8_UNORM D3DFMT_R8G8_B8G8 |
DDS_FOURCC | “RGBG” |
DXGI_FORMAT_G8R8_G8B8_UNORM D3DFMT_G8R8_G8B8 |
DDS_FOURCC | “GRGB” |
* DXGI_FORMAT_R16G16B16A16_UNORM D3DFMT_A16B16G16R16 |
DDS_FOURCC | 36 |
* DXGI_FORMAT_R16G16B16A16_SNORM D3DFMT_Q16W16V16U16 |
DDS_FOURCC | 110 |
* DXGI_FORMAT_R16_FLOAT D3DFMT_R16F |
DDS_FOURCC | 111 |
* DXGI_FORMAT_R16G16_FLOAT D3DFMT_G16R16F |
DDS_FOURCC | 112 |
* DXGI_FORMAT_R16G16B16A16_FLOAT D3DFMT_A16B16G16R16F |
DDS_FOURCC | 113 |
* DXGI_FORMAT_R32_FLOAT D3DFMT_R32F |
DDS_FOURCC | 114 |
* DXGI_FORMAT_R32G32_FLOAT D3DFMT_G32R32F |
DDS_FOURCC | 115 |
* DXGI_FORMAT_R32G32B32A32_FLOAT D3DFMT_A32B32G32R32F |
DDS_FOURCC | 116 |
D3DFMT_DXT2 |
DDS_FOURCC | “DXT2” |
D3DFMT_DXT4 |
DDS_FOURCC | “DXT4” |
D3DFMT_UYVY |
DDS_FOURCC | “UYVY” |
D3DFMT_YUY2 |
DDS_FOURCC | “YUY2” |
D3DFMT_CxV8U8 |
DDS_FOURCC | 117 |
任何 DXGI 格式 | DDS_FOURCC | “DX10” |
* = 可靠的 DDS 读取器必须能够处理这些旧格式代码。 但是,此类 DDS 读取器在编写这些格式代码时应更倾向于使用“DX10”标头扩展,以避免歧义。
** = 由于 DDS 读取器和编写器的常见实现中存在一些长期存在的问题,写出 10:10:10:2 类型数据的最可靠方法是将“DX10”标头扩展与 DXGI_FORMAT 代码“24” (即DXGI_FORMAT_R10G10B10A2_UNORM值) 。 D3DFMT_A2R10G10B10数据应转换为 10:10:10:2 类型数据,然后再写成DXGI_FORMAT_R10G10B10A2_UNORM格式 DDS 文件。