unsigned int mip_map_count= (header->dwFlags & DDSD_MIPMAPCOUNT) ? max( header->dwMipMapCount, 1 ) : 1 ;この項目に 2 以上の値を設定する場合は、dwCaps にも DDSCAPS_MIPMAP を設定して下さい。 ==== dwPfFlags は PixelFormat の有効な情報や形式を表す ====
シンボル | 値 | 内容 |
---|---|---|
DDPF_ALPHAPIXELS | 0x00000001 | RGB 以外に alpha が含まれている。つまり dwRGBAlphaBitMask が有効。 |
DDPF_ALPHA | 0x00000002 | pixel は Alpha 成分のみ含まれている。 |
DDPF_FOURCC | 0x00000004 | dwFourCC が有効。 |
DDPF_PALETTEINDEXED4 | 0x00000008 | * Palet 16 colors (DX9 以降はたぶん使用されない) |
DDPF_PALETTEINDEXED8 | 0x00000020 | * Palet 256 colors (DX10 以降は使用されない) |
DDPF_RGB | 0x00000040 | dwRGBBitCount/dwRBitMask/dwGBitMask/dwBBitMask/dwRGBAlphaBitMask によってフォーマットが定義されていることを示す |
DDPF_LUMINANCE | 0x00020000 | * 1ch のデータが R G B すべてに展開される |
DDPF_BUMPDUDV | 0x00080000 | * pixel が符号付であることを示す (本来は bump 用) DX10以降は使用しない |
シンボル | 値 | 内容 |
---|---|---|
DDSCAPS_ALPHA | 0x00000002 | Alpha が含まれている場合 (あまり参照されない) |
DDSCAPS_COMPLEX | 0x00000008 | 複数のデータが含まれている場合。Palette/Mipmap/Cubemap/VolumeTexture では On にする。 |
DDSCAPS_TEXTURE | 0x00001000 | 常に On |
DDSCAPS_MIPMAP | 0x00400000 | MipMap が存在する場合。(dwFlags の DDSD_MIPMAPCOUNT が On でかつ dwMipMapCount が 2以上の場合に On) |
シンボル | 値 | 内容 |
---|---|---|
DDSCAPS2_CUBEMAP | 0x00000200 | Cubemap の場合 |
DDSCAPS2_CUBEMAP_POSITIVEX | 0x00000400 | Cubemap +X が含まれている |
DDSCAPS2_CUBEMAP_NEGATIVEX | 0x00000800 | Cubemap -X が含まれている |
DDSCAPS2_CUBEMAP_POSITIVEY | 0x00001000 | Cubemap +Y が含まれている |
DDSCAPS2_CUBEMAP_NEGATIVEY | 0x00002000 | Cubemap -Y が含まれている |
DDSCAPS2_CUBEMAP_POSITIVEZ | 0x00004000 | Cubemap +Z が含まれている |
DDSCAPS2_CUBEMAP_NEGATIVEZ | 0x00008000 | Cubemap -Z が含まれている |
DDSCAPS2_VOLUME | 0x00400000 | VolumeTexture の場合 |
- 圧縮テクスチャなど、特殊なフォーマットの定義
- HDR 形式など、D3D9 (DX9) 拡張フォーマットの定義
- DX10 (D3D10) 拡張ヘッダが存在していることを宣言
- dwPfFlags の DDPF_FOURCC が有効
- dwFourCC の値が 'DX10' ( MAKE_FOURCC( 'D','X','1','0' ) == 0x30315844 )
#define MAKE_FOURCC( x, y, z, w ) (((w)<<24)|((z)<<16)|((y)<<8)|(x)) header->dwFourCC= MAKE_FOURCC( 'D', 'X', 'T', '1' );=== FourCC の有効な値 ===
FourCC | format | 解説 |
---|---|---|
'DX10' | DXGI_FORMAT有効 | DX10 拡張ヘッダが存在していることを意味する |
'DXT1' | DXT1 | DXT1, BC1 |
'DXT2' | DXT2 | DXT2 |
'DXT3' | DXT3 | DXT3, BC2 |
'DXT4' | DXT4 | DXT4 |
'DXT5' | DXT5 | DXT5, BC3 |
'BC4U' | BC4 UNORM | BC4-U |
'BC4S' | BC4 SNORM | BC4-S |
'BC5U' | BC5 UNORM | BC5-U |
'BC5S' | BC5 SNORM | BC5-S |
0x00000024 (36) | A16B16G16R16 | R16G16B16A16_UNORM |
0x0000006e (110) | Q16W16V16U16 | R16G16B16A16_SNORM |
0x0000006f (111) | R16F | R16_FLOAT |
0x00000070 (112) | G16R16F | R16G16_FLOAT |
0x00000071 (113) | A16B16G16R16F | R16G16B16A16_FLOAT |
0x00000072 (114) | R32F | R32_FLOAT |
0x00000073 (115) | G32R32F | R32G32_FLOAT |
0x00000074 (116) | A32B32G32R32F | R32G32B32A32_FLOAT |
0x00000075 (117) | CxV8U8 | |
0x0000003f (63) | Q8W8V8U8 | R8G8B8A8_SNORM (nVIDIA の tool のみ DirectX9 texture tool では DDPF_BUMPDUDV で bitmask を返す) |
'ATI2' | 3Dc ATI2 | ATI の Normal 圧縮フォーマット |
'3DC1' | 3Dc ATI1 | ATI/Qualcomm の Texture Tool が生成する。 |
'3DC2' | 3Dc ATI2 | ATI/Qualcomm の Texture Tool が生成する。 |
'ATC ' | ATITC RGB | ATI/Qualcomm の Texture Tool が生成する。 |
'ATCA' | ATITC E-Alpha | ATI/Qualcomm の Texture Tool が生成する。 |
'ATCI' | ATITC I-Alpha | ATI/Qualcomm の Texture Tool が生成する。 |
'ETC1' | ETC1 | ATI/Qualcomm の Texture Tool が生成する。 |
'PTC2' | PVRTC 2bpp (v1) | Imagination PowerVR PVRTexTool が生成する。 |
'PTC4' | PVRTC 4bpp (v1) | Imagination PowerVR PVRTexTool が生成する。 |
- 他にも存在していると思われます。
format (D3D10) | format (D3D9) | dwBitCount | dwRBitMask | dwGBitMask | dwBBitMask | dwRGBAlphaMask | dwFourCC | DX10 Format | dwPfFlags |
---|---|---|---|---|---|---|---|---|---|
B8G8R8A8_UNORM | A8R8G8B8 | 32 | 0x00ff0000 | 0x0000ff00 | 0x000000ff | 0xff000000 | 0 | – | DDPF_RGB|DDPF_ALPHAPIXELS |
R8G8B8A8_UNORM | A8B8G8R8 | 32 | 0x000000ff | 0x0000ff00 | 0x00ff0000 | 0xff000000 | 0 | – | DDPF_RGB|DDPF_ALPHAPIXELS |
R16G16_UNORM | G16R16 | 32 | 0x0000ffff | 0xffff0000 | 0x00000000 | 0x00000000 | 0 | – | DDPF_RGB |
B5G6R5_UNORM | R5G6B5 | 16 | 0x0000f800 | 0x000007e0 | 0x0000001f | 0x00000000 | 0 | – | DDPF_RGB |
R32G32B32A32_FLOAT | A32B32G32R32F | 0 | 0 | 0 | 0 | 0 | 0x00000074 | – | DDPF_FOURCC |
B8G8R8X8_UNORM | X8R8G8B8 | 32 | 0x00ff0000 | 0x0000ff00 | 0x000000ff | 0x00000000 | 0 | – | DDPF_RGB |
– | L16 | 16 | 0x0000ffff | 0x00000000 | 0x00000000 | 0x00000000 | 0 | – | DDPF_LUMINANCE |
– | A8L8 | 16 | 0x000000ff | 0x00000000 | 0x00000000 | 0x0000ff00 | 0 | – | DDPF_LUMINANCE|DDPF_ALPHAPIXELS |
BC7 | – | 0 | 0 | 0 | 0 | 0 | “DX10” | DXGI_FORMAT_BC7_UNORM (98) | DDPF_FOURCC |
BC1 | DXT1 | 0 | 0 | 0 | 0 | 0 | “DXT1” | – | DDPF_FOURCC |
BC1 | DXT1 | 0 | 0 | 0 | 0 | 0 | “DX10” | DXGI_FORMAT_BC1_UNORM (70) | DDPF_FOURCC |
R8G8B8A8_SNORM | Q8W8V8U8 | 32 | 0x000000ff | 0x0000ff00 | 0x00ff0000 | 0xff000000 | 0 | – | DDPF_BUMPDUDV |
R8G8B8A8_SNORM | Q8W8V8U8 | 0 | 0 | 0 | 0 | 0 | 0x0000003f | – | DDPF_FOURCC |
R8G8B8A8_SNORM | Q8W8V8U8 | 0 | 0 | 0 | 0 | 0 | “DX10” | DXGI_FORMAT_R8G8B8A8_SNORM | DDPF_FOURCC |
- Bitmask で表現される場合 (dwPfFlags が DDPF_RGB|DDPF_ALPHAPIXELS の場合)
- FourCC で表現される場合。
- DX10 拡張ヘッダの Format (DXGI_FORMAT) で表現される場合。
- BC6H, BC7 等、Direct3D 10 以降に追加されたフォーマットを格納するには DX10 拡張ヘッダが必須となります。
- Texture Array を格納する場合も DX10 拡張ヘッダが必要です。よって、Bitmask 表現が可能な B8G8R8A8_UNORM や B5G6R5_UNORM 等も、TextureArray 使用時は DXGI_FORMAT による表現になります。
#define MAKE_FOURCC( x, y, z, w ) (((w)<<24)|((z)<<16)|((y)<<8)|(x)) void* memory= malloc( file_size ); ReadFile( file, memory, file_size, &read_size, NULL ); ~ assert( file_size >= sizeof(T_DDSHEADER) ); const T_DDSHEADER* header= reinterpret_cast<const T_DDSHEADER*>( memory ); const unsigned char* data_ptr= reinterpret_cast<const unsigned char*>( memory ) + sizeof(T_DDSHEADER); if( header->dwMagic != 0x20534444 || header->dwSize != 124 ){ // error return false; } unsigned int width= header->dwWidth; unsigned int height= max( header->dwWidth, 1 ); unsigned int depth= (header->dwFlags & DDSD_DEPTH) ? max( header->dwDepth, 1 ) : 1; unsigned int mip_map_count= (header->dwFlags & DDSD_MIPMAPCOUNT) ? max( header->dwMipMapCount, 1 ) : 1; unsigned int array_count= 1; unsigned int face_count= 1; if( header->dwPfFlags & DDPF_FOURCC ){ unsigned int fourCC= header->dwFourCC; if( fourCC == MAKE_FOURCC( 'D','X','1','0' ) ){ // DX10 拡張ヘッダあり // 追加ヘッダの読み込み const T_DDSHEADER_DX10* header10= reinterpret_cast<const T_DDSHEADER_DX10*>( data_ptr ); // ピクセルデータ位置の再計算 data_ptr+= sizeof(T_DDSHEADER_DX10); DXGI_FORMAT format_code= header10->Format; // DXGI_FORMAT による定義 array_count= max( header10->ArraySize, 1 ); }else{ // FourCC による定義 D3DFORMAT や MAKE_FOURCC('D','X','T','1') など switch( fourCC ){ case MAKE_FOURCC('D','X','T','1'): ~ } } }else if( header->dwPfFlags & (DDPF_RGB|DDPF_ALPHAPIXELS|DDPF_ALPHA|DDPF_BUMPDUDV|DDPF_LUMINANCE) ){ // Bitmask による定義 unsigned int bit_count= header->dwRGBBitCount; unsigned int r_mask= header->dwRBitMask; unsigned int g_mask= header->dwGBitMask; unsigned int b_mask= header->dwBBitMask; unsigned int a_mask= header->dwRGBAlphaBitMask; }else{ // error } if( !(header->dwCaps & DDSCAPS_MIPMAP) ){ mip_map_count= 1; } if( !(header->dwCaps2 & DDSCAPS2_VOLUME) ){ depth= 1; } if( header->dwCaps2 & DDSCAPS2_CUBEMAP ){ face_count= 6; // 厳密には DDSCAPS2_CUBEMAP_POSITIVEX ~ の判定が必要 }==== ヘッダ設定コードの例 ====
T_DDSHEADER header; T_DDSHEADER_DX10 header10; memset( &header, 0, sizeof(T_DDSHEADER) ); memset( &header10, 0, sizeof(T_DDSHEADER_DX10) ); bool isdx10= false; header.dwMagic= 0x20534444; header.dwSize= 124; header.dwFlags= DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT; header.dwWidth= width; header.dwHeight= height; header.dwDepth= 1; header.dwMipMapCount= 1; header10.ArraySize= 1; if( ((width * height * bit_count) >> 3) != row_pitch ){ header.dwFlags|= DDSD_PITCH; header.dwPitchOrLinearSize= row_pitch; }else{ header.dwFlags|= DDSD_LINEARSIZE; header.dwPitchOrLinearSize= (width * height * bit_count) >> 3; } if( mipmap_count > 1 ){ header.dwFlags|= DDSD_MIPMAPCOUNT; header.dwCaps|= DDSCAPS_COMPLEX|DDSCAPS_MIPMAP; header.dwMipMapCount= mipmap_count; } if( face_count > 1 ){ header.dwCaps|= DDSCAPS_COMPLEX; header.dwCaps2|= DDSCAPS2_CUBEMAP |DDSCAPS2_CUBEMAP_POSITIVEX |DDSCAPS2_CUBEMAP_NEGATIVEX |DDSCAPS2_CUBEMAP_POSITIVEY |DDSCAPS2_CUBEMAP_NEGATIVEY |DDSCAPS2_CUBEMAP_POSITIVEZ |DDSCAPS2_CUBEMAP_NEGATIVEZ; } if( depth > 1 ){ header.dwCaps|= DDSCAPS_COMPLEX; header.dwCaps2|= DDSCAPS2_VOLUME; header.dwDepth= depth; } if( array_count > 1 ){ header10.ArraySize= array_count; isdx10= true; // Array なら DX10 ヘッダが必須 } header.dwPfSize= 32; if( !isdx10 && BitMask 表現可能 ){ header.dwPfFlags|= DDPF_RGB|DDPF_ALPHAPIXELS; header.dwRGBBitCount= .. header.dwRBitMask= .. header.dwGBitMask= .. header.dwBBitMask= .. header.dwRGBAlphaBitMask= .. }else if( !isdx10 && FourCC 表現が可能 ){ header.dwPfFlags|= DDPF_FOURCC; header.dwFourCC= .. }else{ isdx10= true; header.dwPfFlags|= DDPF_FOURCC; header.dwFourCC= 0x30315844; // 'DX10' // DXGI_FORMAT に変換 header10.Format= dxgi_format; } Write( &header, sizeof(T_DDSHEADER) ); if( isdx10 ){ Write( &header10, sizeof(T_DDSHEADER_DX10) ); }==== fp16 (half) のフォーマットと変換 ==== A32B32G32R32F 等の fp32 形式は IEEE754 そのままなので、 通常 32bit float 値を格納するだけです。 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 = 10bitoffset による指数の表現、正規化された仮数部の隠れbit 等は IEEE754 と同じです。 相互変換の簡単なコード例を載せます。(このコードは特殊な状況を想定していません)
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 ); }==== エンディアンとメモリ並び順 ==== DirectX9 の pixel 形式には A8R8G8B8 等の通常のカラー形式だけでなく A8B8G8R8 や、A2B10G10R10、A32B32G32R32F 等 RGB 順ではなく、BGR 順のフォーマットが増えています。 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 の並び順 ==== 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) |
- 2005/07/10 作成
- 2005/07/11 Q8W8V8U8 の nVIDIA FourCC 追加 (最初間違っていたのであとで修正)
- 2005/07/12 ATI2 FourCC 追加
- 2005/07/13 fp16 変換コードサンプル修正、 符号付ピクセル、 存在しないチャンネルの説明追加
- 2005/07/19 FourCC と D3DFMT の対応について追記
- 2007/03/23 COMPLEX のスペルミス修正、Cubemap の説明追加
- 2015/05/26 Wiki page に変換。DX10 拡張ヘッダについて追記修正。実際の判定コード例を記載。判明している FourCC の追加。