マテリアルを設定して、虎のモデルを描画する

単純なポリゴンで表現される面が集まったものをメッシュ(mesh)と言います。
MyD3D Object Class で、テクスチャを貼り付けたメッシュ(虎のモデル)を回転しながら描画します。
また DirectX の LPD3DXMESH->CloneMeshFVF でクローンを作成して法線ベクトルを設定する方法も説明します。
虎のモデル(X file)は DirectX のサンプルプログラムに添付されているものを使用します。

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

プログラムの説明

  1. 新規作成で空のプロジェクト(Tiger)を作成して下さい。
    プロジェクトのフォルダーに次のファイルを格納して下さい。
    myd3d.h と myd3d.cpp は Object Class Library から取得して下さい。
    Tiger.x と Tiger.bmp は DirectX のサンプルデータとして添付されています。
    ファイル名 ファイルの説明
    Tiger.cpp 説明を参考にして作成して下さい
    myd3d.h MyD3D Object Class ヘッダファイル
    myd3d.cpp MyD3D Object Class プログラムファイル
    Tiger.x 虎のモデルのXファイル
    Tiger.bmp 虎のテクスチャファイル
  2. #define と #include と Direct3D の領域です。
    myd3d が MyD3D Object Class の定義です。
    g_pMesh は3Dモデル(虎)のオブジェクトです。
    g_pMat は material のオブジェクトです。
    g_pTex はテクスチャのオブジェクトです。
    g_Num には X-File に格納されている「属性テーブル」のエントリ数?が格納されます。
    "Tiger.x" が3Dモデル(虎)のファイル名です。
        #define     NAME        "MyD3D Tiger"
        #include    "MyD3D.h"
    
        //Global variables
        MyD3D                   *myd3d   = NULL;     // MyD3D Object Class
        HWND                    g_hWnd;
        LPDIRECT3DDEVICE9       g_pDEV   = NULL;
        LPD3DXMESH              g_pMesh  = NULL;
        D3DMATERIAL9*           g_pMat   = NULL;
        LPDIRECT3DTEXTURE9*     g_pTex   = NULL;
        DWORD                   g_Num    = 0L;
        bool                    g_bActive= false;   // アクティブ状態
        D3DXVECTOR3             ViewForm(0.0f,3.0f,-5.0f);
        char                    XFile[24]= "Tiger.x";
    
        D3DMATERIAL9            Material;
        D3DLIGHT9               Light;
        
  3. WinMain() ではウインドウを生成して、InitGraphics() で DirectX3D を初期化します。
    Render() で虎のメッシュを描画します。
        INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
        {   MSG     msg;
                     :
            HWND hWnd = CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,
                                     100,100,600,600,GetDesktopWindow(),
                                     NULL,wc.hInstance,NULL);
            if (FAILED(InitGraphics(hWnd)))     return FALSE;
                     :
            while(msg.message!=WM_QUIT)
            {   if (PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
                {   TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else    Render();
            }
                     :
        
  4. Direct Graphics の初期化です。
    Object Class をインスタンス化して、DirectX のインターフェースを取得します。
    LoadXFile() で虎のモデル(X-File)を入力します。
    サンプルデータとして添付されている Tiger.x には法線ベクトルが設定されていません。
    myd3d->LoadXFile() で入力すると法線ベクトルが設定されていないときは、設定するようにプログラムしています。
    虎のモデルを表示 に比べて、光源で照らされている部分や影の部分がうまくレンダリングされていることを確認して下さい。
    マテリアルやライトの設定は変化しないので、ここで設定しています。
        HRESULT InitGraphics(HWND hWnd)
        {
            myd3d= new MyD3D(hWnd);
            myd3d->InitD3D(&g_pDEV);
            //虎のモデル(X File)を入力
            g_Num= myd3d->LoadXFile(XFile,&g_pMesh,&g_pMat,&g_pTex);
            if (g_Num==0)
            {   MessageBox(NULL,XFile,"X-File Open Error",MB_OK);
                return E_FAIL;
            }
            myd3d->SetMaterial();
            myd3d->SetLight();
            g_pDEV->SetRenderState(D3DRS_AMBIENT,0x00808080);
            g_pDEV->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);      //カリングを行う
            return S_OK;
        }
        
  5. 虎のモデルを描画する関数です。
    Clear() で画面をクリアします。
    BeginScene() でシーンの開始を設定します。
    SetupMatrices() は描画環境を設定する関数です。
    g_Num には X-File に格納されている「属性テーブル」のエントリ数?が格納されます。
    g_pMat[] と g_pTex[] と g_pMesh->DrawSubset() で虎を描画します。
    EndScene() でシーンの処理を終了します。
    Present() で作成したシーンを描画します。
        VOID Render()
        {
            if (!g_pDEV || !g_bActive)  return;
            //Clear the backbuffer and the zbuffer
            g_pDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(200,200,255),1.0f,0);
            if (SUCCEEDED(g_pDEV->BeginScene()))
            {   //描画環境の設定
                SetupMatrices();
                //虎のメッシュを描画
                for(DWORD i=0; i<g_Num; i++)
                {   g_pDEV->SetMaterial(&g_pMat[i]);
                    g_pDEV->SetTexture(0,g_pTex[i]);
                    g_pMesh->DrawSubset(i);     // Draw the mesh subset
                }
                g_pDEV->EndScene();
            }
            g_pDEV->Present(NULL,NULL,NULL,NULL);
        }
        
  6. 描画環境を設定する関数です。
    ワールド座標をY軸を中心にして回転します。
    D3DXMatrixLookAtLH() で View 座標を設定します。
    D3DXMatrixPerspectiveFovLH() で透視変換の設定をします。
        VOID  SetupMatrices()
        {
            D3DXMATRIX  matView;
            D3DXMATRIX  matProj;
            D3DXMATRIX  matWorld;
            D3DXMATRIX  w;
    
            //View 座標の回転
            D3DXMatrixRotationY(&w,timeGetTime()/1000.0f);
            D3DXMatrixTranslation(&matView,0,0,4.0f);
            matView= w*matView;
            g_pDEV->SetTransform(D3DTS_VIEW,&matView);
            //透視変換の設定
            D3DXMatrixPerspectiveFovLH(&matProj,D3DXToRadian(45.0f),1.0f,1.0f,100.0f);
            g_pDEV->SetTransform(D3DTS_PROJECTION,&matProj);
        }
        
  7. 使用したオブジェクトと領域は終了する前に開放して下さい。
    g_pMeshMat と g_pMeshTex は SAFE_DELETE で開放します。
        VOID Cleanup()
        {
            SAFE_DELETE(g_pMat);
            if (g_pTex)
            {   for(DWORD i=0; i<g_Num; i++)   SAFE_RELEASE(g_pTex[i]);
                SAFE_DELETE(g_pTex);
            }
            SAFE_RELEASE(g_pMesh);
            SAFE_DELETE(mydx3d);
        }
        

【メモ】

虎のモデル(Tiger.x) には法線ベクトルが設定されていません。
従って普通にマテリアルを設定して光源を当ててレンダリングすると真っ黒になります。
物体に光が当たると反射して明るく見えますが、どの方向から光が当たると最も強く反射するかを法線ベクトルで設定します。
Mesh は3次元形状を三角形や四角形の集合で表したもので、そのままレンダリングしたのではポリゴンがごつごつしますが、 ポリゴンの境界に法線ベクトルを設定すると滑らかにレンダリングすることが出来ます。
また Tiger.x には Ambient の値も設定されていないようで、光が当たらない部分(全体的に)暗くなります。
  1. Ambient を設定する方法は簡単です。
    g_pMeshMaterials[i].Ambient の r,g,b に適当な値を設定して下さい。
        for(DWORD i=0; i<g_dwNumMaterials; i++)
        {   g_pMeshMaterials[i]= d3dxMaterials[i].MatD3D;
            g_pMeshMaterials[i].Ambient.r=g_pMeshMaterials[i].Ambient.g=g_pMeshMaterials[i].Ambient.b= 0.5f;
            g_pMeshTextures[i] = NULL;
            if(d3dxMaterials[i].pTextureFilename!=NULL && 
               lstrlen(d3dxMaterials[i].pTextureFilename)>0)
            {   if(FAILED(D3DXCreateTextureFromFile(g_pD3DDevice,
                          d3dxMaterials[i].pTextureFilename,&g_pMeshTextures[i])))
                    MessageBox(NULL,"Could not find texture map","Meshes.exe",MB_OK);
            }
        }
        
  2. 法線ベクトルを設定する方法です。
    1. フラグに D3DFVF_NORMAL を追加して CloneMeshFVF() でクローンを作成します。
    2. D3DXComputeNormals(pTempMesh, NULL) で法線ベクトルを計算します。
    3. SAFE_RELEASE(g_pMesh) で元の Mesh を削除します。
    4. g_pMesh = pTempMesh で新しい Mesh を設定します。
        // 法線ベクトルが設定されていないときの処理
        if (!( g_pMesh->GetFVF() & D3DFVF_NORMAL ))
        {
            ID3DXMesh* pTempMesh;
            g_pMesh->CloneMeshFVF(g_pMesh->GetOptions(), g_pMesh->GetFVF() | D3DFVF_NORMAL, g_pD3DDevice, &pTempMesh);
            D3DXComputeNormals(pTempMesh, NULL);
            SAFE_RELEASE(g_pMesh);
            g_pMesh = pTempMesh;
        }
        
  3. 後はライトとマテリアルを設定して描画して下さい。
    DirectX10 でも同様のプログラムを作成しています。
    Tiger.x を回転しながらマウスで操作する を参照して下さい。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

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

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