VertexBuffer で多角形の筒を描画する

VertexBuffer は描画処理のためにビデオボード上などに確保される高速のメモリ領域です。
DirectX の CreateVertexBuffer で領域を確保して、直接頂点データを割り当てて多角形の筒を描画してみましょう。

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

プログラムの説明

  1. VertexBuffer に割り当てる頂点データの形式です。
    D3DXVECTOR3 は、三次元空間ベクトルで float x,y,z; の要素で構成されます。
    position は三次元空間の XYZ 座標です。
    normal は法線ベクトルの設定で、マテリアルや光源の計算に使用されます。
    D3DVERTEX は MyD3D.h の中で宣言されているのでコメントにしています。
        #define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
        /*
        typedef struct
        {   D3DXVECTOR3 position; // The 3D position for the vertex
            D3DXVECTOR3 normal;   // The surface normal for the vertex
        }   D3DVERTEX;
        */
        
  2. 次の定義は 4面体を回転しながら描画する で使ったものです。
    今回の設定と比べてみて下さい。
        //頂点フォーマット
        #define D3DFVF_VERTEX  (D3DFVF_XYZ | D3DFVF_DIFFUSE)
        typedef struct _D3DLVERTEX_
        {   float   x,y,z;
            DWORD   color;
        }   D3DVERTEX;
    
        //四面体の定義
        D3DVERTEX vtx[6]=
        { { -5,    0,      5,      0xff0000ff  },   //青の頂点
          {  5,    0,      5,      0xffff0000  },   //赤の頂点
          {  0,    8.16f,  2.11f,  0xffffffff  },   //白の頂点
          {  0,    0,     -3.66f,  0xff00ff00  },   //緑の頂点
          { -5,    0,      5,      0xff0000ff  },   //青の頂点
          {  5,    0,      5,      0xffff0000  }    //赤の頂点
        };
        
  3. KAKU は多角形の設定で (KAKU-1) 角形の筒を生成します。
    この値を 4,5,7,10,20,50 などに置き換えて試してみて下さい。
    *myd3d は MyD3D Object Class の定義です。
    g_pVB には割り当てた VertexBuffer のポインタを格納します。
        #include    "MyD3D.h"
        #define      KAKU      6
    
        // Global variables
        MyD3D                   *myd3d   = NULL;    // MyD3D Object Class
        LPDIRECT3DDEVICE9       g_pDEV   = NULL;    // Our rendering device
        LPDIRECT3DVERTEXBUFFER9 g_pVB    = NULL;    // Buffer to hold vertices
        
  4. MyD3D Object Class をインスタンス化して、インターフェースを取得します。
    InitGeometry() で Vertex Buffer に多角形の筒を生成します。
        HRESULT InitDevices(HWND hWnd)
        {
            myd3d= new MyD3D(hWnd);
            myd3d->InitD3D(&g_pDEV);
            if (FAILED(InitGeometry()))     return FALSE;
            return S_OK;
        }
        
  5. InitGeometry() 関数で VertexBuffer を割り当てて多角形の筒を生成します。
    CreateVertexBuffer() で VertexBuffer を作成します。
    Lock() で領域をロックして VertexBuffer へのポインタを取得します。
    VertexBuffer に TRIANGLESTRIP(一辺を共有する連続三角形)の形式に合わせて、多角形の筒の座標を登録します。
    Unlock() で VertexBuffer のロックを解除します。
        HRESULT InitGeometry()
        {   D3DVERTEX*  pVertices;
    
            if (FAILED(g_pDEV->CreateVertexBuffer(KAKU*2*sizeof(D3DVERTEX),
                               0,D3DFVF_VERTEX,D3DPOOL_DEFAULT,&g_pVB,NULL)))
                return E_FAIL;
            if (FAILED(g_pVB->Lock(0,0,(void**)&pVertices,0)))  return E_FAIL;
            for(DWORD i=0; i<KAKU; i++)
            {   FLOAT theta = (2*D3DX_PI*i)/(KAKU-1);
                pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
                pVertices[2*i+0].normal   = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );
                pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
                pVertices[2*i+1].normal   = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );
            }
            g_pVB->Unlock();
            return S_OK;
        }
        
  6. 多角形の筒を描画します。
    SetupMatrices() でマテリアルを設定します。
    SetStreamSource() でレンダリングソースとして VertexBuffer を設定します。
    DrawPrimitive() でレンダリングします。
        VOID Render()
        {
            g_pDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,255),1.0f,0);
            g_pDEV->BeginScene();
            SetupMatrices();
            g_pDEV->SetStreamSource(0,g_pVB,0,sizeof(D3DVERTEX));
            g_pDEV->SetFVF(D3DFVF_VERTEX);
            g_pDEV->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2*KAKU-2);
            g_pDEV->EndScene();
            g_pDEV->Present(NULL,NULL,NULL,NULL);
        }
        
  7. 描画環境とマテリアルの設定です。
    X軸とY軸の周期をずらせて回転し、多角形を様々な角度から描画しています。
          D3DXMatrixRotationX(&matw, timeGetTime()/500.0f);
          D3DXMatrixRotationY(&matw, timeGetTime()/350.0f);
        
    回転が速すぎる(遅すぎる)ときは 500.0f と 350.0f の値を調整して下さい。
    SetMaterial() で円筒の色を設定しています。
    SetLight() で光源を設定します。
    g_pDEV->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE) でカリングを無効にします。
    SetRenderState(D3DRS_AMBIENT,0x00606060) は環境光の設定です。
        VOID SetupMatrices()
        {   D3DXMATRIX matWorld,matw;
            D3DXMATRIX matView;
            D3DXMATRIX matProj;
    
            //World 座標の設定
            D3DXMatrixIdentity(&matWorld);
            D3DXMatrixRotationX(&matw, timeGetTime()/500.0f);
            D3DXMatrixMultiply(&matWorld, &matWorld, &matw);
            D3DXMatrixRotationY(&matw, timeGetTime()/350.0f);
            D3DXMatrixMultiply(&matWorld, &matWorld, &matw);
            g_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));
            g_pDEV->SetTransform(D3DTS_VIEW, &matView);
            //透視変換の設定
            D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
            g_pDEV->SetTransform(D3DTS_PROJECTION, &matProj);
            mydx3d->SetMaterial(0.7f, 0.7f, 0.0f);
            mydx3d->SetLight();
            g_pDEV->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
            g_pDEV->SetRenderState(D3DRS_AMBIENT,0x00606060);
        }
        
  8. WinMain() 関数では描画の大きさに合わせてウインドウサイズを設定して下さい。

【課題】

円柱や円錐を描画するプログラムを作成して下さい。

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

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

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

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