D3D で三角形を描画する

三角形の頂点に「赤緑青」を設定して DirectX の DrawPrimitiveUP で描画します。
DirectX9 3D(三次元)グラフィックスを表示する基本的なプログラムです。

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

プロジェクトの作成

  1. 空の新規プロジェクト(Sample)を作成して下さい。
    プロジェクトの作成方法は Direct3D デバイスを取得する を参照して下さい。
  2. ページの後部より全ソースコード(triangle.txt)を取得して、Sample.cpp の名前でプロジェクト(Sample)のフォルダーに格納して下さい。
    プロジェクト/既存項目の追加から格納したファイルをプロジェクトに追加して下さい。
  3. 以前は「プロジェクト/プロパティ」から「リンカ/入力/追加する依存関係」でライブラリをリンクしていたのですが、 このプログラムでは #pragma を使っているのでリンクの操作は不要です。
    詳細は Windows Guid から「パスの設定」を参照して下さい。
        #pragma once
        #pragma comment(lib,"d3d9.lib")
        #pragma comment(lib,"d3dx9.lib")
        #pragma comment(lib,"dxguid.lib")
        
  4. ビルドから実行を選ぶと、コンパイルに続いて実行が行われます。
    ページ先頭の画面が表示されたら完成です。

プログラムの説明

DirectX9 3D(三次元)グラフィックスを表示する基本的なプログラムです。
  1. 頂点フォーマットの設定です。
    ウインドウ上のピクセル座標で三個の頂点座標(X,Y,Z)と同次座標ベクトルのW成分と頂点の色を定義しています。
    X, Y, Z の回転と平行移動まで考えると、4次での計算が必要になります。
    そこで、次数を合わせるためにW成分(常に 1.0)を付加して計算します。
    頂点座標の順序(左回りと右回り)を入れ替えてみて下さい。
    ポリゴン(多角形)が裏向きになって描画されなくなります。
        //頂点フォーマット
        #define FVF_VERTEX   (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
        typedef struct
        {   float       x,y,z;    // 頂点座標
            float       rhw;      // 常に 1.0
            D3DCOLOR    diffuse;  // 反射光
        }   D3DVERTEX;
    
        D3DVERTEX v[3]=
        { {  300.0f, 100.0f, 0.0f, 1.0f, 0xffff0000  },     //頂点=赤
          {  450.0f, 250.0f, 0.0f, 1.0f, 0xff00ff00  },     //右辺=緑
          {  150.0f, 250.0f, 0.0f, 1.0f, 0xff0000ff  },     //左辺=青
        };
        
  2. Direct3D のグローバル領域です。
    g_pD3D は Direct3D のオブジェクトです。
    g_pDEV は Direct3D のデバイスです。
        LPDIRECT3D9             g_pD3D= NULL;
        LPDIRECT3DDEVICE9       g_pDEV= NULL;
        
  3. WinMain() 関数です。
    参照しないパラメータ名は省略しています。
    D3Dの初期化以外は2Dの時と同じ要領です。
    実は3Dプログラムの最初の難関が Direct3D デバイスの取得です。
    このプログラムでは最も簡単な方法でデバイスを取得していますが、全ての状況下で動くとは限りません。
    私はハードやプログラムの種類により何種類かの関数を用意して使い分けています。
        INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
        {   MSG     msg;
                     :
                     :
            // Initialize Direct3D
            if (FAILED(Init3DDev(hWnd)))    return FALSE;
                     :
                     :
        
  4. 出来るだけ簡単な方法でデバイスを取得してみました。
    全ての状況下(ハード構成 etc)で動くとは限らないことをご承知下さい。
        HRESULT Init3DDev(HWND hWnd)
        {   D3DDISPLAYMODE          d3ddm;
            D3DPRESENT_PARAMETERS   d3dpp;
    
            if (NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION)))    return E_FAIL;
            if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))   return E_FAIL;
            ZeroMemory(&d3dpp,sizeof(d3dpp));
            d3dpp.Windowed                  = TRUE;                     // ウィンドウモード
            d3dpp.SwapEffect                = D3DSWAPEFFECT_DISCARD;    // 映像信号に同期してフリップする
            d3dpp.EnableAutoDepthStencil    = TRUE;                     // デプスバッファ(Zバッファ)とステンシルバッファを作成
            d3dpp.AutoDepthStencilFormat    = D3DFMT_D16;               // デプスバッファとして16bitを使う
            d3dpp.BackBufferFormat          = d3ddm.Format;             // カラーモードの指定
    
            if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
                                     D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pDEV)))
                return E_FAIL;
    
            return S_OK;
        }
        
  5. CALLBACK 関数の MsgProc() です。
    今回のような静止した画像は Windows と同じように WM_PAINT: から描画することも出来るので試して下さい。
        case WM_PAINT:
            Draw();
            break;
        
    サンプルプログラムでは、メッセージループから描画しています。
    ESCAPE キーが押されるとプログラムを終了します。
        LRESULT WINAPI MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
        {
            switch(msg)
            {   case WM_DESTROY:
                    PostQuitMessage(0);
                    break;
                case WM_KEYDOWN:
                    switch(wParam)
                    {   case VK_ESCAPE:
                            DestroyWindow(hWnd);
                            break;
                    }
                    break;
                default:
                    return DefWindowProc(hWnd, msg, wParam, lParam);
            }
            return 0;
        }
        
  6. 三角形を描画する関数 Draw() です。
    Clear() で画面をクリアします。
    BeginScene() でシーンの開始を設定します。
    SetFVF() で頂点フォーマットをセットします。
    DrawPrimitiveUP() で三角形を描画します。
    EndScene() でシーンの処理を終了します。
    Present() で作成したシーンを描画します。
        void Draw(void)
        {   //黒で塗りつぶして消去
            g_pDEV->Clear(0, NULL, (D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER), D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0);
            if (SUCCEEDED(g_pDEV->BeginScene()))
            {   //デバイスに使用する頂点フォーマットをセットする
                g_pDEV->SetFVF(FVF_VERTEX);
                //頂点データ(v)を渡して描画する
                g_pDEV->DrawPrimitiveUP(D3DPT_TRIANGLELIST,1,v,sizeof(D3DVERTEX));
                g_pDEV->EndScene();
            }
            g_pDEV->Present(NULL,NULL,NULL,NULL);
        }
        
  7. オブジェクトを開放する関数です。
    取得したオブジェクトは必ず開放して下さい。
        void Cleanup(void)
        {   SAFE_RELEASE(g_pDEV);
            SAFE_RELEASE(g_pD3D);
        }
        

【演習】

  1. 頂点座標の順序(左回りと右回り)を入れ替えてみて下さい。
    カリングが設定されていると裏面が描画されません。
  2. 三角形の頂点の色を変更してみて下さい。
  3. 四角形を表示してみて下さい。
    四角形は三角形を二個組み合わせて表示します。
  4. 三角形のポリゴンを組み合わせて四面体を表示してみて下さい。
    独立した三角形を組み合わせることもできますが、隣り合った三角形の一辺がつながるように頂点を定義(TRIANGLESTRIP)する方が簡単です。

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

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

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

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