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でんち | [メニューに戻る] | フルパワー全開 |