DDS は DirectDrawSurface の意味です。 もともと DirectX7 以前に使われていた DirectDraw の Surface 構造をそのままファイルに 格納したものだと思われます。
そのため単純な画像フォーマットとしてはやや異質で、 ヘッダには使わないシンボルや変数等が残っています。 ヘッダを見てもよくわからないのですが、 実際に使われるのはそのうちごく一部だけです。 以下このページに載せるのはそのうち使用されると思われる シンボルだけを抜粋しました。
DirectX8 以降 DirectDraw も DirectDrawSurface も無くなりましたが ファイルフォーマットとしての DDS のみ残っています。 DXT1〜DXT5 の圧縮形式や CubeMapTexture を格納できること、 また普及具合やツールがそろっている点を考えると結局 DDS が便利なようです。
各チャンネル 8bit 以上 (R G B A それぞれ 10bit〜32bit ) のカラー値を取り扱えるフォーマットやツールにはあまり選択肢がありません。 ハード側ではこれら HDR テクスチャを扱えるものの ツールやソフトウエア側では 各チャンネル 8bit ( 32bit A8R8G8B8 ) までのものがほとんどです。
対応ツールが増えると良いな、と思い わかる範囲で今回調べた情報を公開させていただきます。
新しいページに Direct3D 10 以降の DDS 拡張ヘッダについての解説を追加しました。
新しい DDS フォーマットの解説は下記のリンクよりどうぞ。(2015/05/26)
// ヘッダ構造体 struct _iDDSHEAD { public: DWORD dwMagic; // == 0x20534444 ' SDD' DWORD dwSize; // == 124 DWORD dwFlags; // ヘッダ内の有効な情報 DDSD_* の組み合わせ DWORD dwHeight; // 画像の高さ x size DWORD dwWidth; // 画像の幅 y size DWORD dwPitchOrLinearSize; // 横1 line の byte 数 (pitch) // または 1面分の byte 数 (linearsize) DWORD dwDepth; // 画像の奥行き z size (Volume Texture 用) DWORD dwMipMapCount; // 含まれている mipmap レベル数 DWORD dwReserved1[11]; DWORD dwPfSize; // == 32 DWORD dwPfFlags; // pixel フォーマットを表す DDPF_* の組み合わせ DWORD dwFourCC; // フォーマットが FourCC であらわされる場合のみ DWORD dwRGBBitCount; // 1 pixel の bit 数 DWORD dwRBitMask; // RGB format 時の mask DWORD dwGBitMask; // RGB format 時の mask DWORD dwBBitMask; // RGB format 時の mask DWORD dwRGBAlphaBitMask; // RGB format 時の mask DWORD dwCaps; // mipmap 等のフラグ指定用 DWORD dwCaps2; // cube/volume texture 等のフラグ指定用 DWORD dwReservedCaps[2]; DWORD dwReserved2; }; |
DDSD_CAPS | 0x00000001 | dwCaps/dwCpas2 が有効 |
DDSD_HEIGHT | 0x00000002 | dwHeight が有効 |
DDSD_WIDTH | 0x00000004 | dwWidth が有効 |
DDSD_PITCH | 0x00000008 | dwPitchOrLinearSize が Pitch を表す |
DDSD_PIXELFORMAT | 0x00001000 | dwPfSize/dwPfFlags/dwRGB〜 等の直接定義が有効 |
DDSD_MIPMAPCOUNT | 0x00020000 | dwMipMapCount が有効 |
DDSD_LINEARSIZE | 0x00080000 | dwPitchOrLinearSize が LinearSize を表す |
DDSD_DEPTH | 0x00800000 | dwDepth が有効 |
DDPF_ALPHAPIXELS | 0x00000001 | RGB 以外に alpha が含まれている |
DDPF_ALPHA | 0x00000002 | pixel は Alpha 成分のみ |
DDPF_FOURCC | 0x00000004 | dwFourCC が有効 |
DDPF_PALETTEINDEXED4 | 0x00000008 | Palet 16 colors (DX9 ではたぶん使用されない) |
DDPF_PALETTEINDEXED8 | 0x00000020 | Palet 256 colors |
DDPF_RGB | 0x00000040 | dwRGBBitCount/dwRBitMask/dwGBitMask/dwBBitMask/dwRGBAlphaBitMask によってフォーマットが定義されていることを示す |
DDPF_LUMINANCE | 0x00020000 | 1ch のデータが R G B すべてに展開される |
DDPF_BUMPDUDV | 0x00080000 | pixel が符号付であることを示す (本来は bump 用) |
DDSCAPS_ALPHA | 0x00000002 | Alpha が含まれている場合 (あまり参照されない) |
DDSCAPS_COMPLEX | 0x00000008 | 複数のデータが含まれている場合 Palette/Mipmap/Cube/Volume 等 |
DDSCAPS_TEXTURE | 0x00001000 | 常に 1 |
DDSCAPS_MIPMAP | 0x00400000 | MipMap が存在する場合 |
DDSCAPS2_CUBEMAP | 0x00000200 | Cubemap が存在する場合 |
DDSCAPS2_CUBEMAP_POSITIVEX | 0x00000400 | |
DDSCAPS2_CUBEMAP_NEGATIVEX | 0x00000800 | |
DDSCAPS2_CUBEMAP_POSITIVEY | 0x00001000 | |
DDSCAPS2_CUBEMAP_NEGATIVEY | 0x00002000 | |
DDSCAPS2_CUBEMAP_POSITIVEZ | 0x00004000 | |
DDSCAPS2_CUBEMAP_NEGATIVEZ | 0x00008000 | |
DDSCAPS2_VOLUME | 0x00400000 | VolumeTexture の場合 |
dwFourCC に入る値は 4文字を組み合わせた ascii 値ですが、 直接 32bit の値が用いられているものもあるようです。
この値は d3d9types.h にある D3DFORMAT の enum 定義値そのままです。 たとえば R32F の場合 0x72 == D3DFMT_R32F == 114 となります。
そのため同じフォーマットでも Bitmask で表現可能な場合、 RGB Bitmask で表現される場合と dwFourCC の D3DFMT 値で表現される場合の 2種類の DDS ヘッダが存在し得ることになります。 実際 nVIDIA のツールと DX9 付属のツールで Q8W8V8U8 のヘッダが異なっていました。 より柔軟なツールにするなら、両方対応しておく必要がありそうです。
FourCC | format | |
'1TXD' | DXT1 | |
'2TXD' | DXT2 | |
'3TXD' | DXT3 | |
'4TXD' | DXT4 | |
'5TXD' | DXT5 | |
'2ITA' | 3Dc ATI2 | ATI の Normal 圧縮フォーマット |
0x00000024 | A16B16G16R16 | |
0x0000006e | Q16W16V16U16 | |
0x0000006f | R16F | |
0x00000070 | G16R16F | |
0x00000071 | A16B16G16R16F | |
0x00000072 | R32F | |
0x00000073 | G32R32F | |
0x00000074 | A32B32G32R32F | |
0x00000075 | CxV8U8 | |
0x0000003f | Q8W8V8U8 | (nVIDIA の tool のみ DirectX9 texture tool では DDPF_BUMPDUDV で bitmask を返す) |
format | dwBitCount | dwRBitMask | dwGBitMask | dwBBitMask | AlphaMask | dwFourCC | dwPfFlags |
A8R8G8B8 | 32 | 0x00ff0000 | 0x0000ff00 | 0x000000ff | 0xff000000 | 0 | DDPF_RGB|DDPF_ALPHAPIXELS |
A8B8G8R8 | 32 | 0x000000ff | 0x0000ff00 | 0x00ff0000 | 0xff000000 | 0 | DDPF_RGB|DDPF_ALPHAPIXELS |
G16R16 | 32 | 0x0000ffff | 0xffff0000 | 0x00000000 | 0x00000000 | 0 | DDPF_RGB |
R5G6B5 | 16 | 0x0000f800 | 0x000007e0 | 0x0000001f | 0x00000000 | 0 | DDPF_RGB |
L16 | 16 | 0x0000ffff | 0x00000000 | 0x00000000 | 0x00000000 | 0 | DDPF_LUMINANCE |
Q8W8V8U8 | 32 | 0x000000ff | 0x0000ff00 | 0x00ff0000 | 0xff000000 | 0 | DDPF_BUMPDUDV |
DXT1 | 0 | 0 | 0 | 0 | 0 | "DXT1" | DDPF_FOURCC |
A32B32G32R32F | 0 | 0 | 0 | 0 | 0 | 0x00000074 | DDPF_FOURCC |
A8L8 | 16 | 0x000000ff | 0x00000000 | 0x00000000 | 0x0000ff00 | 0 | DDPF_LUMINANCE|DDPF_ALPHAPIXELS |
A16B16G16R16F 等の fp16 (half) の場合 CPU ネィティブな形式ではありません。 CPU 上で演算を行う場合は変換が必要になります。
fp16 は s10e5 の形をしており、符号1bit、指数部 5bit、 仮数部 10bit となります。
bit15 ------- bit0 s eeeee ffffffffff ------------------ s = 1bit sign e = 5bit offset 15 ( 0〜31 の値の範囲で 15 を 0とみなす) f = 10bit |
相互変換の簡単なコード例を載せます。 (このコードは特殊な状況を想定していません)
ui32 F32to16( float fval ) { ui32 ival= * (ui32*)( &fval ); if( !ival ){ return 0; } si32 e=((ival & 0x7f800000)>>23) - 127 + 15; if( e < 0 ){ return 0; }else if( e > 31 ){ e= 31; } ui32 s= ival & 0x80000000; ui32 f= ival & 0x007fffff; return ((s>>16)&0x8000) | ((e<<10) & 0x7c00) | ((f>>13) & 0x03ff); } |
float F16to32( ui32 ival ) { if( !ival ){ return 0.0f; } ui32 s= ival & 0x8000; si32 e=((ival & 0x7c00) >>10) - 15 + 127; ui32 f= ival & 0x03ff; ui32 fval= (s<<16) | ((e <<23)&0x7f800000) | (f<<13); return * (float*)( &fval ); } |
Intel CPU は little endian なので 32bit ARGB はメモリに格納されると 'B' 'G' 'R' 'A' の順で並びます。
Shader 等、4 要素の vector は x y z w がそれぞれカラー演算時 r g b a に対応するため、 このカラー並びはあまり都合が良くありません。
そのため ABGR というピクセル並びにしておけばメモリ上で 'R' 'G' 'B' 'A' になるのでそのまま x y z w としてアクセスすることができます。
シェーダー互換性のために今後は A B G R が一般的になっていくのかもしれません。 フォーマットはますますややこしくなりますが。
符号付ピクセルのテクスチャフォーマット Q8W8V8U8, V8U8 等は 2の補数表現でそのまま格納されます。
Pixel Shader の _bx2 modifier ( (n-0.5)*2 ) のように unsigned の 0〜1.0 へ畳み込んだ値ではありません。 そのため (1.0, 1.0, 1.0, 1.0) を Q8W8V8U8 に変換すると 7f 7f 7f 7f という値になります。
チャンネルとしては U V W Q がそれぞれ x y z w = r g b a に対応しています。
R8G8B8 等、A チャンネルが存在しないフォーマットや、 R だけのフォーマット等があります。
原則として未定義のチャンネルはデフォルト値 1.0 を持つようです。 ただしカラーチャンネルの場合は例外があるようです。 A チャンネルの未定義は常に 1.0 です。
また法線用の圧縮形式では、未定義のチャンネルを 計算で求める必要があります。 CxV8U8、3Dc (ATI2) はそれぞれ x y の値から z を算出します。
(z= sqrt( 1-(x*x+y*y) ) )
3Dc (ATI2) は符号なしなので、x y に対して事前に _bx2 相当 ( (n-0.5)*2 ) の変換が必要になります。 また z 値の算出は Shader 側で行う必要があり、 テクスチャフォーマットとしては単なる 2ch の R8G8 です。 正規化されたベクトル以外の値を入れて使うこともできます。
L8 L16 等の DDPF_LUMINANCE チャンネルは bitmask のフォーマット上 R として定義されますがカラー 3チャンネル全部にコピーされます。
CUBEMAP はマニュアルにあるとおり X+/X-/Y+/Y-/Z+/Z- 順番に並びます。 問題は各面の上下構造で、この並びは次のようになっています。 一般的な Cross 形式の Cubemap では Z- の UpVect は上下逆になります。
面の向き | 上方向(UpVect) |
X + | Yup (0,1,0) |
X - | Yup (0,1,0) |
Y + | Z- (0,0,-1) |
Y - | Z+ (0,0,1) |
Z + | Yup (0,1,0) |
Z - | Yup (0,1,0) |
Hyperでんち | [メニューに戻る] | フルパワー全開 |