X-FILE を描画する

X-FILE を描画する

DirectX10 で X-FILE インターフェイスを使って描画します。

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

プロジェクトの説明

  1. DirectX10 のプロジェクトで X-FILE を描画するだけなら Cone.x を回転しながら描画するTiger.x を回転しながらマウスで操作する がお勧めです。
    D3DXLoadMeshFromX() が使えなくなった DirectX10 ですが、X-FILE のインターフェイスは使えるようです。
    ちょっと面倒なのですが、X-FILE のインターフェイスを使ってモデルを描画してみましょう。 (^_^;)
    描画する X-FILE は メッシュを生成して X-FILE に保存する で作成した「頂点座標と法線ベクトル」のモデルです。
    長方体のモデルに加えて、ティーポットのモデルも作成することが出来ます。
    頂点座標と法線ベクトル以外で構成されているモデルの場合は、少しプログラムの修正が必要です。
    プログラムは 立方体を光源で照らして描画する を元に作成しました。
    描画の基本は、このページを参照して下さい。
  2. EmptyProject10 には DirectX10 と DirectX9 のソースファイルが格納されていて、両方のプログラムが可能です。
    今回は純粋な DirectX10 のアプリケーション MultiMon10 を使うことにします。
    DirectX Sample Browser で MultiMon10 のプロジェクトを作成して下さい。
    MultiMon10 のプロジェクトをコンパイルして、正常に実行されることを確かめて下さい。
    エラーが発生するときや、正常に実行出来ないときは、残念ながら現在の構成は相性が悪いようです。
  3. ソースプログラムと Shader と X-FILE を圧縮形式で提供します。
    MultiMon10 のプロジェクトのフォルダーに格納して下さい。
    ファイル名 説明
    ViewXFile.zip 圧縮ファイル
  4. #include と領域の宣言です。
    X-FILE のインターフェイスを使うので "template.h" を取り込みます。
    *vtx が頂点座標のポインタで *idx が Index のポインタです。
    *nV が頂点座標の数で *nF が面(Face)の数です。
    #include "DXUT.h"
    #include "template.h"
    
    ID3D10Effect*               g_pEffect = NULL;
    ID3D10InputLayout*          g_pLayout = NULL;
    ID3D10EffectTechnique*      g_pRender = NULL;
    ID3D10Buffer*               g_pVertexBuffer = NULL;
    ID3D10Buffer*               g_pIndexBuffer = NULL;
    ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
    ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
    D3DXMATRIX                  g_World;
    D3DXMATRIX                  g_View;
    D3DXMATRIX                  g_Projection;
    
    D3DVERTEX                   *vtx= NULL;     //頂点座標のポインタ
    DWORD                       *idx= NULL;     //Indexのポインタ
    DWORD                       *nV;            //頂点座標の数
    DWORD                       *nF;            //面(Face)の数
    
  5. OnD3D10CreateDevice() から X-FILE をロードする LoadXfile() 関数を呼び出します。
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice,
            const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
    {
        ・・・
    
        LoadXfile();
        // Create vertex buffer
        D3D10_BUFFER_DESC bd;
        bd.Usage = D3D10_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( D3DVERTEX ) * (*nV);
        bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
        bd.CPUAccessFlags = 0;
        bd.MiscFlags = 0;
        D3D10_SUBRESOURCE_DATA InitData;
        InitData.pSysMem = vtx;
        hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
        if( FAILED(hr) )    return hr;
    
        // Set vertex buffer
        UINT stride = sizeof( D3DVERTEX );
        UINT offset = 0;
        pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
    
        // Create index buffer
        bd.Usage = D3D10_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( DWORD ) * (*nF)*3;
        bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
        bd.CPUAccessFlags = 0;
        bd.MiscFlags = 0;
        InitData.pSysMem = idx;
        hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
        if( FAILED(hr) )    return hr;
    
        ・・・
    
  6. X-FILE のデータをメモリにロードする LoadXfile() 関数です。
    model.x を入力して、頂点座標を *vtx に、法線ベクトルを *idx に設定します。
    最初に DirectXFileCreate() で X-FILE のインターフェイスを取得します。
    CreateEnumObject() でテンプレートデータを列挙する IDirectXFileEnumObject を取得します。
    GetNextDataObject() で順番にデータを取り出します。
    GetType() で GUID を取得して、ユニークIDでデータを識別します。
    GetData() で template で定義されている名前を指定してデータを取得します。
    Mesh は階層構造になっています。
    子のテンプレートデータにアクセスするには GetNextObject() で IDirectXFileObject を取得して、 QueryInterface() で子の IDirectXFileData を取得します。
    // X-FILE のデータをメモリにロードする。
    void  LoadXfile()
    {   DWORD                   i;
        IDirectXFile            *pDXFile = NULL;
        IDirectXFileEnumObject  *pDXEnum = NULL;
        IDirectXFileData        *pDXData = NULL;
        IDirectXFileObject      *pChildObj = NULL;
        IDirectXFileData        *pDXChildData = NULL;
        const GUID              *pguid;
        DWORD                   Size;       //X-FILE データ項目のサイズ
        float                   *pVect;     //X-FILE の Vector Pointer
        DWORD                   *pFaces;    //X-FILE の Faces Pointer
        DWORD                   *pDW;       //X-FILE の DWORD Pointer
        float                   *pNormal;   //X-FILE の Normal Pointer
    
        DirectXFileCreate( &pDXFile );
        if (FAILED(pDXFile->RegisterTemplates(str,(DWORD)strlen(str)))) goto error;
        // ファイルを解析してテンプレートデータを列挙する
        if (FAILED(pDXFile->CreateEnumObject("model.x",DXFILELOAD_FROMFILE,&pDXEnum)))
            goto error;
    
        while(SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData)))
        {   // テンプレートの型チェック
            pDXData->GetType(&pguid);
            if (*pguid==Mesh)       // Mesh のデータ
            {   //nVertices を取得
                pDXData->GetData("nVertices",&Size,(void**)&nV);
                //vertices を取得
                pDXData->GetData("vertices",&Size,(void**)&pVect);
                vtx= (D3DVERTEX *)GlobalAlloc(GMEM_FIXED,sizeof(D3DVERTEX)*(*nV));
                //nFaces を取得
                pDXData->GetData("nFaces",&Size,(void**)&nF);
                idx= (DWORD *)GlobalAlloc(GMEM_FIXED,sizeof(DWORD)*(*nF)*3);
                //faces を取得
                pDXData->GetData("faces",&Size,(void**)&pFaces);
                //頂点座標と Index を設定
                for(i=0; i<*nV; i++)
                {   (vtx+i)->x= *pVect;
                    (vtx+i)->y= *(pVect+1);
                    (vtx+i)->z= *(pVect+2);
                    pVect+= 3;
                }
                for(i=0; i<*nF; i++)
                {   *(idx+i*3)= *(pFaces+1);
                    *(idx+i*3+1)= *(pFaces+2);
                    *(idx+i*3+2)= *(pFaces+3);
                    pFaces+= 4;
                }
    
                //子テンプレートデータにアクセス
                if (FAILED(pDXData->GetNextObject(&pChildObj)))     break;
                if (FAILED(pChildObj->QueryInterface(IID_IDirectXFileData,(void**)&pDXChildData)))  break;
                // テンプレートの型チェック
                pDXChildData->GetType(&pguid);
                if (*pguid==MeshNormals)    // MeshNormals のデータ
                {   //nNormals を取得
                    pDXChildData->GetData("nNormals",&Size,(void**)&pDW);
                    //normals を取得
                    pDXChildData->GetData("normals",&Size,(void**)&pNormal);
                    //法線ベクトルを設定
                    for(i=0; i<*nV; i++)
                    {   (vtx+i)->nx= *pNormal;
                        (vtx+i)->ny= *(pNormal+1);
                        (vtx+i)->nz= *(pNormal+2);
                        pNormal+= 3;
                    }
                }
            }
        }
        goto exit;
    
    error:
        MessageBox(NULL,L"X-FILE のロードに失敗しました",L"X=FILE Error",MB_OK);
    exit:
        SAFE_RELEASE(pDXChildData);
        SAFE_RELEASE(pChildObj);
        SAFE_RELEASE(pDXData);
        SAFE_RELEASE(pDXEnum);
        SAFE_RELEASE(pDXFile);
    }
    
  7. OnD3D10FrameRender() 関数でモデルを描画します。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
                ・・・
        // Render the cube
        D3D10_TECHNIQUE_DESC techDesc;
        g_pRender->GetDesc( &techDesc );
        for( UINT p = 0; p < techDesc.Passes; ++p )
        {
            g_pRender->GetPassByIndex( p )->Apply(0);
            pd3dDevice->DrawIndexed( (*nF)*3, 0, 0 );
        }
                ・・・
    

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