インデックスバッファを使用して立体を描画する(DirectX9 32/64bit)

icon 項目のみ表示/展開表示の切り替え

概要

Direct X 9を用い、インデックスバッファにより立体を回転させながら描画する。なおライトを使用しております。
下の図は、頂点バッファのものを用いています。

ソースコードのダウンロード  indexbuffer.zip

ソースコードの説明

_tWinMain

最初に実行される関数です。
最初にウィンドウを作成し、InitDevices関数でDirect Xの初期化を行います。
その後通常の_tWinMain関数と同じ様にメッセージループを構成しますが、メッセージの取り出しにGetMessage関数ではなく、PeekMessage関数を使用し、メッセージがないときもループが回るようにします。メッセージがないときにDraw関数を呼び出し描画を行います。

Init3Devices

Direct Xの初期化を行います。初期化は、できるだけハードウェアの能力を生かせるように、

①ハードウェアによる頂点処理・ハードウェアによるラスタ処理
②ソフトウェアによる頂点処理・ハードウェアによるラスタ処理
③ソフトウェアによる頂点処理・ソフトウェアによるラスタ処理

の順番でデバイスの作成を試みます。

InitGeometry

CreateVertexBufferにより頂点バッファを作成します。
Lockメソッドによりバッファを書き込み可能な状態にします。
横方向の四角4面と上方向の四角1面は別個に描画することにします。
よって、法線方向をわける必要があるので、別々の頂点に分けます。
書き込み後にUnlockメソッドを実行します。
CreateIndexBufferによりインデックスバッファを作成します。
Lockメソッドによりバッファを書き込み可能な状態にします。
書き込み後にUnlockメソッドを実行します。

SetupMatrices

Render関数から呼び出されます。

D3DXMatrixRotationX,D3DXMatrixRotationZ,D3DXMatrixMultiply,SetTransform

X軸及びZ軸を中心に立体を回転させます。

D3DMatrixLookAtLH

D3DMatrixPerspectiveFovLH

ワールド座標をビュー座標に変換する。ワールド座標のどの方向からどの範囲を見るか(描画するか)を設定する。この関数は、左手座標(Xが右、Yが上、Zが奥行方向で奥 左手で手のひらを上側がにし人差し指をX方向に向けた時における親指のさしている方向がZ値が増える方向である。)においてワールド座標をビュー座標に変換する。
描画する遠近それぞれのZ値、画面の縦横比(アスペクト)、Y方向の視野角を指定する。
その他に、光源と球とトーラスのマテリアルを設定します。

Render

画面のクリア Clear

レンタリング開始 BeginScene

頂点バッファの登録 SetStreamSource

レンタリングを行う DrawPrimitive

レンタリング終了 EndScene

バッファの内容を表示 Present

Cleanup

Init3Devicesで作成したデバイスと頂点バッファを開放します。

WndProc

ウィンドウプロシージャーです。ウィンドウ関係のメッセージを処理します。通常WM_PAINTメッセージにより再描画を行いますが、スピードが要求される場合は、前期のとおり別の場所で処理しています。

コンパイル方法

Visual C++ 2008
Microsoft DirectX SDK June 2010をインストールをあらかじめ行っておく
プロジェクトに下記のパスを追加(64bit Windowsで64bitの実行ファイルを作成する場合)
includeパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include
LibパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64
を追加

ソースコード

//      インデックスバッファを用いた立体の表示 Direct X 9

#define     szClassName      TEXT("IndexBuffer 3DBOX")

#include <windows.h>
#include <d3dx9.h>
#include <tchar.h>

#pragma once
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")

#define SAFE_RELEASE(p)         { if (p) { (p)->Release();  (p)=NULL; } }

typedef struct _D3DVERTEX{
        D3DXVECTOR3 position; // 頂点座標
    D3DXVECTOR3 normal;   // 法線方向
}   D3DVERTEX;

D3DPRESENT_PARAMETERS   D3DPPWin;
LPDIRECT3DDEVICE9       pDEV=0;
LPDIRECT3D9             pD3D=0;
D3DMATERIAL9            Material;
D3DLIGHT9               Light;
LPDIRECT3DVERTEXBUFFER9 pVB = 0;    // 頂点バッファ
LPDIRECT3DINDEXBUFFER9 pIB = 0; //      インデックスバッファ

#define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)

BOOL InitApp(HINSTANCE, WNDPROC, TCHAR*);
BOOL InitInstance(HINSTANCE, TCHAR*, int);
HWND hWnd;
HRESULT InitDevices(HWND hWnd); // デバイス/モード等の初期化
HRESULT InitGeometry(void);     // 頂点バッファの初期化
LRESULT WINAPI WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
void Render(void);// 描画処理
void SetupMatrices(void);// 描画環境の設定
void Cleanup(void);     // オブジェクトの開放


INT WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lptsCmdLine, INT nCmdShow){
        MSG     msg;

    if (!hPrevInst) {
        if (!InitApp(hInst,WndProc, szClassName))    //    ウィンドウクラスの登録
            return FALSE;
    }
    if (!InitInstance(hInst, szClassName, nCmdShow)) {    // ウィンドウの作成
        return FALSE;
    }
        
        if (FAILED(InitDevices(hWnd)))
                return FALSE;

    ShowWindow(hWnd,SW_SHOWDEFAULT);
    UpdateWindow(hWnd);
    ZeroMemory(&msg,sizeof(msg));
    while(msg.message!=WM_QUIT){
                if (PeekMessage(&msg,NULL,0U,0U,PM_REMOVE)){
                        TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
                        Render();
    }
    Cleanup();
    return 0;
}

BOOL InitApp(HINSTANCE hInst,WNDPROC WndProc,TCHAR* Name){
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = (TCHAR*)Name;
    return (RegisterClass(&wc));
}

BOOL InitInstance(HINSTANCE hInst, TCHAR* Name, int nCmdShow){
    hWnd = CreateWindow(Name,
            Name,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInst,
            NULL);
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}

// デバイス/モード等の初期化
HRESULT InitDevices(HWND hWnd){
        D3DDISPLAYMODE          dmode;
        HRESULT     hr;

    // デバイス/モード等の初期化
    if (pD3D==NULL)
                pD3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (pD3D==NULL)
                return E_FAIL;
    //現在のディスプレイモードを得る
    if (FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&dmode)))
                return E_FAIL;

    // D3DDeviceオブジェクトの作成
    ZeroMemory(&D3DPPWin, sizeof(D3DPPWin));
    D3DPPWin.BackBufferFormat           = dmode.Format;
    D3DPPWin.BackBufferCount            = 1;
    D3DPPWin.SwapEffect                 = D3DSWAPEFFECT_DISCARD;
    D3DPPWin.Windowed                   = TRUE;
    D3DPPWin.EnableAutoDepthStencil     = TRUE;
    D3DPPWin.AutoDepthStencilFormat     = D3DFMT_D16;
    D3DPPWin.Flags                      = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
        
        hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
    if (FAILED(hr)){
                hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
        if (FAILED(hr)){
                        hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
            if (FAILED(hr)){
                                MessageBox(NULL,TEXT("Create Device Error"),TEXT("Surface Error"),MB_OK);
                                return E_FAIL;
                        }
        }
    }
        if (FAILED(InitGeometry()))
                return FALSE;
    return S_OK;
}

HRESULT InitGeometry(void){             // 頂点バッファの初期化
        D3DVERTEX*  p;

    if (FAILED(pDEV->CreateVertexBuffer( 12*sizeof(D3DVERTEX), 0,D3DFVF_VERTEX,D3DPOOL_DEFAULT,&pVB,NULL)))
        return E_FAIL;
    if (FAILED(pVB->Lock(0,0,(void**)&p,0)))
                return E_FAIL;

/*
 座標(左手座標系)

  Y   Z
  |  /
  | /
  |/
  0-----X

D3DPT_TRIANGLESTRIP
   1   3    5

   2   4    6


  頂点番号

     /1 
      / |   ?
    /   |    ?
  /     |     ?3
 7 ?     |    /|
 |  ?    0  /  |
 |   ?    / ?  |
 |/  ?5/    ? |
 6?    |       2
   ?   |     /
    ?  |   /
       4    

7=8 5=9 7=10 3=11
*/

        p[0].position= D3DXVECTOR3( 0.0f ,-0.707f, 1.0f );
        p[0].normal= D3DXVECTOR3( 0.0f ,0,1.0f );
        p[1].position= D3DXVECTOR3( 0.0f ,0.707f, 1.0f );
        p[1].normal= D3DXVECTOR3( 0.0f ,0.0f, 1.0f );

        p[2].position= D3DXVECTOR3( 1.0f ,-0.707f, 0.0f );
        p[2].normal= D3DXVECTOR3( 1.0f ,0.0f, 0.0f );
        p[3].position= D3DXVECTOR3( 1.0f ,0.707f, 0.0f );
        p[3].normal= D3DXVECTOR3( 1.0f ,0.0f, 0.0f );

        p[4].position= D3DXVECTOR3( 0.0f ,-0.707f, -1.0f );
        p[4].normal= D3DXVECTOR3( 0.0f ,0.0f, -1.0f );
        p[5].position= D3DXVECTOR3( 0.0f ,0.707f, -1.0f );
        p[5].normal= D3DXVECTOR3( 0.0f ,0.0f,-1.0f );

        p[6].position= D3DXVECTOR3( -1.0f ,-0.707f, 0.0f );
        p[6].normal= D3DXVECTOR3( -1.0f ,-0.0f, 0.0f );
        p[7].position= D3DXVECTOR3( -1.0f ,0.707f, 0.0f );
        p[7].normal= D3DXVECTOR3( -1.0f ,0.0f, 0.0f );

        p[8].position= D3DXVECTOR3( -1.0f ,0.707f, 0.0f );
        p[8].normal= D3DXVECTOR3( 0.0f ,1.0f, 0.0f );
        p[9].position= D3DXVECTOR3( 0.0f ,0.707f,1.0f );
        p[9].normal= D3DXVECTOR3( 0.0f ,0.707f, 0.0f );

        p[10].position= D3DXVECTOR3(0.0f ,0.707f, -1.0f );
        p[10].normal= D3DXVECTOR3( 0.0f ,0.707f, 0.0f );
        p[11].position= D3DXVECTOR3( 1.0f ,0.707f,0.0f );
        p[11].normal= D3DXVECTOR3( 0.0f ,0.707f, 0.0f );
        
        pVB->Unlock();

        if( FAILED( pDEV->CreateIndexBuffer( 14 *sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16,
        D3DPOOL_DEFAULT, &pIB,NULL ) ) )
                return E_FAIL;
        WORD* pI;

        if( FAILED( pIB->Lock( 0,                 // Fill from start of the buffer.
                      0, // Size of the data to load.
                      (VOID**)&pI, // Returned index data.
                      0 ) ) )            // Send default flags to the lock.
                return E_FAIL;
        pI[0]=1;
        pI[1]=0;
        pI[2]=3;
        pI[3]=2;
        pI[4]=5;
        pI[5]=4;
        pI[6]=7;
        pI[7]=6;
        pI[8]=1;
        pI[9]=0;

        pI[10]=8;
        pI[11]=9;
        pI[12]=10;
        pI[13]=11;

        pIB->Unlock();

    return S_OK;
}

LRESULT WINAPI WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam){
    switch(msg){
           case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hWnd,msg,wParam,lParam);
}

// 描画処理
void Render(void){
    pDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
    pDEV->BeginScene();
    SetupMatrices();
    pDEV->SetStreamSource(0,pVB,0,sizeof(D3DVERTEX));
        pDEV->SetIndices(pIB);
    pDEV->SetFVF(D3DFVF_VERTEX);
        pDEV->DrawIndexedPrimitive(  D3DPT_TRIANGLESTRIP,0,0,10,0,8);
        pDEV->DrawIndexedPrimitive(  D3DPT_TRIANGLESTRIP,8,0,4,0,2);
        
        pDEV->EndScene();
    pDEV->Present(NULL,NULL,NULL,NULL);
}

// 描画環境の設定
void SetupMatrices(void){
        D3DXMATRIX matWorld,matw;
    D3DXMATRIX matView;
    D3DXMATRIX matProj;

    //World 座標の設定
    D3DXMatrixIdentity(&matWorld);

        float rr=timeGetTime()/628.0f;

    D3DXMatrixRotationX(&matw, rr);
    D3DXMatrixMultiply(&matWorld, &matWorld, &matw);
    D3DXMatrixRotationZ(&matw, rr / 4.0f );
    D3DXMatrixMultiply(&matWorld, &matWorld, &matw);
    pDEV->SetTransform(D3DTS_WORLD, &matWorld);
    //View 座標の設定
    D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3( 0.0f, 3.0f,-5.0f ),
                       &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f));
    pDEV->SetTransform(D3DTS_VIEW, &matView);
    //透視変換の設定
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
    pDEV->SetTransform(D3DTS_PROJECTION, &matProj);

        float r=0.486f;
        float g=0.433f;
        float b=0.185f;
    ZeroMemory(&Material,sizeof(D3DMATERIAL9));
    Material.Diffuse.r= r;
    Material.Diffuse.g= g;
    Material.Diffuse.b= b;
    Material.Ambient.r= r;
    Material.Ambient.g= g;
    Material.Ambient.b= b;
    Material.Specular.r= 4*r;
    Material.Specular.g= 4*g;
    Material.Specular.b= 4*b;
    Material.Emissive.r= 0.0f;
    Material.Emissive.g= 0.0f;
    Material.Emissive.b= 0.0f;
    Material.Power= 50;
    pDEV->SetMaterial(&Material);

        r=1.0f;
        g=1.0f;
        b=1.0f;

    ZeroMemory(&Light,sizeof(D3DLIGHT9));
    Light.Type = D3DLIGHT_DIRECTIONAL;
    Light.Diffuse.r= r;
    Light.Diffuse.g= g;
    Light.Diffuse.b= b;
    Light.Specular.r= r;
    Light.Specular.g= g;
    Light.Specular.b= b;
    Light.Ambient.r= r/2.0f;
    Light.Ambient.g= g/2.0f;
    Light.Ambient.b= b/2.0f;
    D3DXVec3Normalize((D3DXVECTOR3*)&Light.Direction,&D3DXVECTOR3(1.0f,-1.5f,0.7f));
    pDEV->SetLight(0,&Light);
    pDEV->LightEnable(0,TRUE);
    pDEV->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
    pDEV->SetRenderState(D3DRS_AMBIENT,0x00606060);
}

// オブジェクトの開放
void Cleanup(void){
    SAFE_RELEASE(pVB);
    SAFE_RELEASE(pDEV);
    SAFE_RELEASE(pD3D);
}