頂点シェーダを使う

頂点シェーダを使って正四面体の View 座標を回転しながら描画します。
最も簡単な頂点シェーダのサンプルプログラムです。

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

プログラムの概要

  1. ビューと透視変換マトリックスと頂点の色を設定するだけの最も簡単な頂点シェーダを用意します。
  2. 正四面体の頂点フォーマットを配列で定義します。
  3. 頂点シェーダのソースコード(color.vsh)を入力してシェーダを作成します。
  4. Vertex Buffer を割り当てて、正四面体の頂点データをコピーします。
  5. Vertex Buffer から頂点シェーダを使って正四面体を描画します。
  6. このプログラムは、ハードウエアがシェーダの機能をサポートしていなければ動きません。
    またシェーダ機能をサポートしているデバイスを選択することも重要です。
  7. プログラムの作成手順としては、汎用のシェーダで動くことを確認してから専用のシェーダを使って下さい。

プログラムの説明

  1. #include と #define と DirectX オブジェクトの定義です。
    *myd3d が MyD3D Object Class の定義です。
    g_pVB が Vertex Buffer Object で、g_Shader が Vertex Shader です。
        /************************************************/
        /*  DirectX9 Vertex Shader のテスト    前田 稔  */
        /************************************************/
        #define     NAME        "Vertex Shader"
        #include    "MyD3D.h"
    
        // Global variables
        MyD3D                   *myd3d   = NULL;        // MyD3D Object Class
        LPDIRECT3DDEVICE9       g_pDEV   = NULL;
        LPDIRECT3DVERTEXSHADER9 g_Shader = NULL;        //Vertex Shader
        LPDIRECT3DVERTEXBUFFER9 g_pVB    = NULL;        //Vertex Buffer
        D3DXMATRIX              g_View;                 //View 座標
        D3DXMATRIX              g_Proj;                 //プロジェクション
        
  2. 中心座標を 0,0,0 に設定して、四面体の頂点座標と色を定義しました。
        #define D3DFVF_VERTEX  (D3DFVF_XYZ | D3DFVF_DIFFUSE)
        struct D3DVERTEXCOR
        {
            float       x,y,z;
            D3DCOLOR    color;
        };
    
        //四面体の定義
        struct D3DVERTEXCOR vtx[]=
        { { -5,   -4.08f,   2.89f,    0xff0000ff  },   //青の頂点
          {  5,   -4.08f,   2.89f,    0xffff0000  },   //赤の頂点
          {  0,    4.08f,   0,        0xffffffff  },   //白の頂点(中央)
          {  0,   -4.08f,  -5.77f,    0xff00ff00  },   //緑の頂点
          { -5,   -4.08f,   2.89f,    0xff0000ff  },   //青の頂点
          {  5,   -4.08f,   2.89f,    0xffff0000  },   //赤の頂点
        };
        
  3. 取得したオブジェクトを開放します。
    g_pDEV は MyD3D Object Class の Constructor で開放されます。
        VOID Cleanup()
        {
            SAFE_RELEASE(g_Shader);
            SAFE_RELEASE(g_pVB);
            SAFE_DELETE(myd3d);
        }
        
  4. 頂点シェーダの作成です。
    color.vsh をアセンブルして Shader を作成します。
        HRESULT InitVertexShader()
        {   LPD3DXBUFFER pVS;
    
            if (FAILED(D3DXAssembleShaderFromFile("color.vsh",NULL,NULL,0,&pVS,NULL)))  return E_FAIL;
            if(FAILED(g_pDEV->CreateVertexShader((DWORD*)pVS->GetBufferPointer(),&g_Shader)))
            {   pVS->Release();  return E_FAIL;  }
            pVS->Release();
            return S_OK;
        }
        
  5. Vertex Buffer を取得して、正四面体のモデルを生成します。
    モデルの原型はメモリ上で定義しているので、実質的には Vertex Buffer にコピーするだけです。
        HRESULT InitGeometry()
        {   void       *lpVertices;
            HRESULT    hr;
    
            hr= g_pDEV->CreateVertexBuffer(6*sizeof(D3DVERTEXCOR),0,D3DFVF_VERTEX,D3DPOOL_DEFAULT,&g_pVB,NULL);
            if (FAILED(hr))     return  E_FAIL;
            // 頂点バッファのコピー
            hr= g_pVB->Lock(0, sizeof(vtx), (LPVOID*)&lpVertices, 0);
            if (FAILED(hr))     return E_FAIL;
            memcpy(lpVertices, vtx, sizeof(vtx));
            g_pVB->Unlock();
            return S_OK;
        }
        
  6. デバイス/モード等の初期化です。
    MyD3D Object Class をインスタンス化して、デバイスを取得します。
    InitVertexShader() で Shader を作成します。
    InitGeometry() で、正四面体を Vertex Buffer に生成します。
        HRESULT InitDevices(HWND hWnd)
        {
            myd3d= new MyD3D(hWnd);
            myd3d->InitD3D(&g_pDEV);
            if (FAILED(InitVertexShader()))
            {   ERMSG("Init Vertex Error");  return  E_FAIL;  }
            if (FAILED(InitGeometry()))
            {   ERMSG("InitGeometry Error");  return  E_FAIL;  }
            return S_OK;
        }
        
  7. Vertex Shader を使って四面体を描画します。
    ビュー座標を v(0,5,20) を基点にして Rotate() で回転しながら描画します。
    SetVertexShader() でカスタム Vertex Shader を設定します。
    SetVertexShaderConstantF(0,(float*)&m,4) で透視変換マトリックスを0番~3番のレジスタに設定します。
    SetStreamSource() で Vertex Buffer の四面体を設定します。
    DrawPrimitive() で四面体を描画します。
        VOID Render()
        {   D3DXVECTOR3     v(0,5,20);      //視点の原点
    
            if (!myd3d)     return;
            g_pDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,60,40),1.0f,0);
    
            g_pDEV->BeginScene();
            //View 座標の回転
            myd3d->Rotate(&v,&D3DXVECTOR3(0,0,0),timeGetTime()/50.0f,1);
            D3DXMatrixLookAtLH(&g_View,(D3DXVECTOR3*)&v,&D3DXVECTOR3(0,0,0),&D3DXVECTOR3(0,1,0));
            D3DXMatrixPerspectiveFovLH(&g_Proj,D3DX_PI/4,800.0f/600.0f,0.0f,100.0f);
            //四面体を専用の Shader を使って描画
            g_pDEV->SetVertexShader(g_Shader);                  //頂点シェーダー設定
            D3DXMATRIX  m;
            D3DXMatrixMultiply(&m,&g_View,&g_Proj);             //視点座標変換+透視変換を頂点シェーダで行う
            D3DXMatrixTranspose(&m,&m);                         //セットするのは転置行列
            g_pDEV->SetVertexShaderConstantF(0,(float*)&m,4);   //視点・透視変換
    
            g_pDEV->SetStreamSource(0,g_pVB,0,sizeof(D3DVERTEXCOR));
            g_pDEV->SetFVF(D3DFVF_VERTEX);                      //頂点フォーマット設定
            g_pDEV->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,4);
            g_pDEV->EndScene();
    
            g_pDEV->Present(NULL, NULL, NULL, NULL);
        }
        
  8. MsgProc(), WinMain() はいつもと同じです。
    InitDevices() でデバイスの設定と初期化を行います。
    Render() でレンダリングを行います。
    Cleanup() で全てのオブジェクトとリソースを開放します。

頂点シェーダ(color.vsh) のソースコードです。

m4x4 oPos,v0,c0 でビューと透視変換マトリックスを設定します。
mov oD0,v1 で頂点の色を設定します。
頂点シェーダの説明は DirectX 9.0 のヘルプファイル/DirectX Graphics/DirectX Graphics の高度なトピック/ピクセル シェーダを参照して下さい。
//c0-c3      ビュー+透視変換マトリックス
//;
//;v0         頂点の座標値
//;v1         色情報

//;座標変換

vs.2.0
dcl_position v0
dcl_color v1
m4x4 oPos,v0,c0
mov oD0,v1

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

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

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