sdkmesh の形式

XFILE⇒sdkmesh(MeshConvert)のプログラムを調べます。
.sdkmesh のファイルはバイナリー形式で作成されていて、そのままメモリーに読み込まれます。
従って、DirectX にとっては編集の必要が無い、効率の良い形式かも知れません。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. X-FILE を sdkmesh に変換するプロジェクトは XFILE ⇒ sdkmesh を参照して下さい。
    DXUT メッシュの作成は IntermediateMesh.cpp(.h) で行われています。
    bool CIntermediateMesh::SaveAsSDKMesh( WCHAR* szFileName ) {  } がその関数です。
    この関数を調べれば DXUT メッシュの内容がなんとなく解りそうです。
    sdkmesh に書き出される主要なデータは、IntermediaMesh.h の class CIntermediateMesh の中でスタックとして定義されています。
    スタックになっていますが、通常の簡単なモデルの場合は、各領域は1個だけアロケートされます。
    CStack<INTERMEDIATE_VERTEX_BUFFER*>   m_VertexBufferArray;
    CStack<INTERMEDIATE_INDEX_BUFFER*>    m_IndexBufferArray;
    CStack<INTERMEDIATE_MESH*>            m_MeshArray;
    CStack<INTERMEDIATE_SUBSET*>          m_SubsetArray;
    CStack<INTERMEDIATE_FRAME*>           m_FrameArray;
    CStack<INTERMEDIATE_MATERIAL*>        m_MaterialArray;
    
  2. SDKMESH_HEADER です。
    struct SDKMESH_HEADER
    {
        //Basic Info and sizes
        UINT Version;               //65000000
        BYTE IsBigEndian;           //Byte順情報 00
        UINT64 HeaderSize;          //ヘッダーサイズ A8010000 00000000
        UINT64 NonBufferDataSize;
        UINT64 BufferDataSize;
    
        //Stats
        UINT NumVertexBuffers;
        UINT NumIndexBuffers;
        UINT NumMeshes;
        UINT NumTotalSubsets;
        UINT NumFrames;
        UINT NumMaterials;
    
        //Offsets to Data
        UINT64 VertexStreamHeadersOffset;
        UINT64 IndexStreamHeadersOffset;
        UINT64 MeshDataOffset;
        UINT64 SubsetDataOffset;
        UINT64 FrameDataOffset;
        UINT64 MaterialDataOffset;
    };
    
  3. SaveAsSDKMesh() では最初に SDKMESH_HEADER 情報を出力します。
    ヘッダーの情報は大体決まっていますが、メッシュの形式やサイズにより多少違いがあります。
        SDKMESH_HEADER fileheader;
        fileheader.Version = SDKMESH_FILE_VERSION;
        fileheader.IsBigEndian = m_bBigEndian;
        fileheader.HeaderSize = HeaderSize;
        fileheader.NonBufferDataSize = NonBufferDataSize; 
        fileheader.BufferDataSize = BufferDataSize;
        fileheader.NumVertexBuffers = m_VertexBufferArray.GetCount();
        fileheader.NumIndexBuffers = m_IndexBufferArray.GetCount();
        fileheader.NumMeshes = m_MeshArray.GetCount();
        fileheader.NumTotalSubsets = m_SubsetArray.GetCount();
        fileheader.NumFrames = m_FrameArray.GetCount();
        fileheader.NumMaterials = m_MaterialArray.GetCount();
        fileheader.VertexStreamHeadersOffset = sizeof( SDKMESH_HEADER );
        fileheader.IndexStreamHeadersOffset = fileheader.VertexStreamHeadersOffset + m_VertexBufferArray.GetCount() * sizeof(SDKMESH_VERTEX_BUFFER_HEADER);
        fileheader.MeshDataOffset = fileheader.IndexStreamHeadersOffset + m_IndexBufferArray.GetCount() * sizeof(SDKMESH_INDEX_BUFFER_HEADER);
        fileheader.SubsetDataOffset = fileheader.MeshDataOffset + m_MeshArray.GetCount() * sizeof(SDKMESH_MESH);
        fileheader.FrameDataOffset = fileheader.SubsetDataOffset + m_SubsetArray.GetCount() * sizeof(SDKMESH_SUBSET);
        fileheader.MaterialDataOffset = fileheader.FrameDataOffset + m_FrameArray.GetCount() * sizeof(SDKMESH_FRAME);
    
        retval = fwrite( &fileheader, sizeof(SDKMESH_HEADER), 1, fp );
    
  4. 次に SDKMESH_VERTEX_BUFFER_HEADER を出力します。
    ここには、頂点データの個数やサイズなどが記録されています。
    NumVertices が頂点データの数です。
    SizeBytes が頂点データ領域のサイズです。
    StrideBytes が頂点データ1個分のサイズです。
    ID3D10Buffer* pVB10; から頂点データの実体が格納されます。
    struct SDKMESH_VERTEX_BUFFER_HEADER
    {   UINT64 NumVertices;
        UINT64 SizeBytes;
        UINT64 StrideBytes;
        D3DVERTEXELEMENT9 Decl[MAX_VERTEX_ELEMENTS];    //32
        union
        {   UINT64 DataOffset;	//(This also forces the union to 64bits)
            IDirect3DVertexBuffer9* pVB9;
    #ifdef D3D10_SDK_VERSION
            ID3D10Buffer*           pVB10;
    #endif
        };
    };
    
  5. 次に SDKMESH_INDEX_BUFFER_HEADER を出力します。
    ID3D10Buffer* pIB10; からインデックスの実体が格納されます。
    struct SDKMESH_INDEX_BUFFER_HEADER
    {
        UINT64 NumIndices;
        UINT64 SizeBytes;
        UINT IndexType;
        union
        {   UINT64 DataOffset;  //(This also forces the union to 64bits)
            IDirect3DIndexBuffer9* pIB9;
    #ifdef D3D10_SDK_VERSION
            ID3D10Buffer*          pIB10;
    #endif
        };
    };
    
  6. 次に SDKMESH_MESH を出力します。
    UINT* pSubsets; から Subset が始まります。
    UINT* pFrameInfluences; から頂点データの実体が格納されます。
    struct SDKMESH_MESH
    {
        char    Name[MAX_MESH_NAME];  //100
        BYTE NumVertexBuffers;
        UINT    VertexBuffers[MAX_VERTEX_STREAMS];  //16
        UINT IndexBuffer;
        UINT NumSubsets;
        UINT NumFrameInfluences; //aka bones
    
        D3DXVECTOR3 BoundingBoxCenter;
        D3DXVECTOR3 BoundingBoxExtents;
    
        union
        {
            UINT64 SubsetOffset;//Offset to list of subsets (This also forces the union to 64bits)
            UINT* pSubsets;     //Pointer to list of subsets
        };
        union
        {
            UINT64 FrameInfluenceOffset;//Offset to list of frame influences (This also forces the union to 64bits)
            UINT* pFrameInfluences;     //Pointer to list of frame influences
        };
    };
    
  7. 次に SDKMESH_SUBSET を出力します。
    struct SDKMESH_SUBSET
    {
        char Name[MAX_SUBSET_NAME];	//100
        UINT MaterialID;
        UINT PrimitiveType;
        UINT64 IndexStart;
        UINT64 IndexCount;
        UINT64 VertexStart;
        UINT64 VertexCount;
    };
    
  8. 次に SDKMESH_FRAME を出力します。
    struct SDKMESH_FRAME
    {
        char Name[MAX_FRAME_NAME];	//100
        UINT Mesh;
        UINT ParentFrame;
        UINT ChildFrame;
        UINT SiblingFrame;
        D3DXMATRIX Matrix;
        UINT AnimationDataIndex;  //Used to index which set of keyframes transforms this frame
    };
    
  9. 次に SDKMESH_MATERIAL を出力します。
    struct SDKMESH_MATERIAL
    {   char    Name[MAX_MATERIAL_NAME];  //100
        // Use MaterialInstancePath
        char    MaterialInstancePath[MAX_MATERIAL_PATH];  //260
        // Or fall back to d3d8-type materials
        char    DiffuseTexture[MAX_TEXTURE_NAME];   //260
        char    NormalTexture[MAX_TEXTURE_NAME];    //260
        char    SpecularTexture[MAX_TEXTURE_NAME];  //260
        D3DXVECTOR4 Diffuse;
        D3DXVECTOR4 Ambient;
        D3DXVECTOR4 Specular;
        D3DXVECTOR4 Emissive;
        FLOAT Power;
        union
        {   UINT64 Force64_1;               //Force the union to 64bits
            IDirect3DTexture9* pDiffuseTexture9;
    #ifdef D3D10_SDK_VERSION
            ID3D10Texture2D*	pDiffuseTexture10;
    #endif
        };
        union
        {   UINT64 Force64_2;               //Force the union to 64bits
            IDirect3DTexture9* pNormalTexture9;
    #ifdef D3D10_SDK_VERSION
            ID3D10Texture2D*	pNormalTexture10;
    #endif
        };
        union
        {   UINT64 Force64_3;		//Force the union to 64bits
            IDirect3DTexture9* pSpecularTexture9;
    #ifdef D3D10_SDK_VERSION
            ID3D10Texture2D*	pSpecularTexture10;
    #endif
        };
        union
        {   UINT64 Force64_4;		//Force the union to 64bits
    #ifdef D3D10_SDK_VERSION
            ID3D10ShaderResourceView*	pDiffuseRV10;
    #endif
        };
        union
        {   UINT64 Force64_5;		//Force the union to 64bits
    #ifdef D3D10_SDK_VERSION
            ID3D10ShaderResourceView*	pNormalRV10;
    #endif
        };
        union
        {   UINT64 Force64_6;		//Force the union to 64bits
    #ifdef D3D10_SDK_VERSION
            ID3D10ShaderResourceView*	pSpecularRV10;
    #endif
        };
    };
    
  10. 3Dモデル(頂点データ)の実体を出力します。
    頂点データは「座標(XYZ), 法線(XYZ), テクスチャ座標(UV)」などで構成されます。
    頂点座標(XYZ) と法線ベクトル(XYZ) で構成される三角形ポリゴンの場合は、次のようになります。
    Pad は Word 境界に合わせるためのパディングです。
          0        4         8        C                 説明
     8B0                     00000000 FFFF7FBF      頂点0(-1, 1, 0)
                             Subset   -1(頂点0)
     8C0  FFFF7F3F 00000000  00000000 00000000      法線0(0, 0, -1)
          1        0         0(法線0) 0
     8D0  FFFF7FBF 00000000  00000000 FFFF7F3F      頂点1(1, 1, 0)
          -1       0(Pad)    0        1(頂点1)
     8E0  FFFF7F3F 00000000  00000000 00000000      法線1(0, 0, -1)
          1        0         0(法線0) 0
     8F0  FFFF7FBF 00000000  00000000 00000000      頂点2(0, -1, 0)
          -1       0(Pad)    0        0(頂点2)
     900  FFFF7FBF 00000000  00000000 00000000      法線1(0, 0, -1)
          -1       0         0(法線)  0
     910  FFFF7FBF 00000000  00000000 00000000
          -1       0(Pad)
    
  11. IntermediateMesh.cpp(1167) から頂点データを書き出しています。
        //VertexData
        for( UINT i=0; i<m_VertexBufferArray.GetCount(); i++ )
        {
            INTERMEDIATE_VERTEX_BUFFER* pVBH = m_VertexBufferArray.GetAt(i);
            retval = fwrite( pVBH->pVertices, (size_t)pVBH->SizeBytes, 1, fp );
            if( retval != 1 )   goto Error;
    
            //pad
            UINT64 alignsize = Align4k( pVBH->SizeBytes );
            BYTE nothing = 0;
            for( UINT64 b=0; b<alignsize - pVBH->SizeBytes; b++ )
            {
                retval = fwrite( ¬hing, sizeof(BYTE), 1, fp );
                if( retval != 1 )   goto Error;
            }
        }
    

超初心者のプログラム入門(DirectX10 game program)