次はインデックスバッファオブジェクトを生成する処理を作ってインデックスバッファを使った描画の方法を書いていきます。
インデックスバッファとは?
インデックスバッファとは頂点バッファのデータを効率良く使うために使用される情報です。
無くても対応はできますが、無駄なデータを減らして最適な描画を行う事が出来ます。
例えば四角形を作る際に4つの頂点で描画をしていました。
これがもし2つの四角形を一度に描画しようと思うとどうすればいいでしょうか?
1つは2回描画処理を呼び出すという方法があります。
ただ一般的にDrawコールと呼ばれるDrawPrimitiveなどの関数には大きな処理負荷が掛かってきます。
そのDrawコールの回数を減らすには頂点を増やして一度で2つ書いていきます。
単純に頂点バッファのみで2つ描画するには下記のような書き方になります。
const SimpleVertex vertices[12] = { // 1つ目の左上側 { 10.0f, 10.0f, 0.0f, 1.0f, 0xffff7f7f }, { 50.0f, 10.0f, 0.0f, 1.0f, 0xff7fff7f }, { 10.0f, 50.0f, 0.0f, 1.0f, 0xff7f7fff }, // 1つ目の右下側 { 10.0f, 50.0f, 0.0f, 1.0f, 0xff7f7fff }, { 50.0f, 10.0f, 0.0f, 1.0f, 0xff7fff7f }, { 50.0f, 50.0f, 0.0f, 1.0f, 0xffffffff }, // 2つ目の左上側 { 110.0f, 110.0f, 0.0f, 1.0f, 0xffff7f7f }, { 150.0f, 110.0f, 0.0f, 1.0f, 0xff7fff7f }, { 110.0f, 150.0f, 0.0f, 1.0f, 0xff7f7fff }, // 2つ目の右下側 { 110.0f, 150.0f, 0.0f, 1.0f, 0xff7f7fff }, { 150.0f, 110.0f, 0.0f, 1.0f, 0xff7fff7f }, { 150.0f, 150.0f, 0.0f, 1.0f, 0xffffffff }, };
バッファのサイズが一気に大きくなりました。
次に描画処理
pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 4);
D3DPT_TRIANGLESTRIP→D3DPT_TRIANGLELISTに変わって描画するポリゴン数も2→4になりました。
何故、四角形が二つで先ほどの倍の8個ではないのか?と疑問に思った方もいると思います。
もしD3DPT_TRIANGLESTRIPのまま頂点も8個で描画してしまうとポリゴンがつながってしまうのでこんな感じになってしまいます。
これじゃ思っていたのと違いますよね?
なので複数の矩形を描画するときはD3DPT_TRIANGLELISTを使って重複する頂点バッファをいくつも持たなければ出来ないので無駄なデータが多くなります。
インデックスバッファはこの無駄なデータを最小限の情報で補ってしまおうというものです。
インデックスバッファの生成
インデックスバッファもオブジェクトを生成する関数を作成していきます。
// インデックスバッファの生成 IDirect3DIndexBuffer9* CreateIndexBuffer(const UINT16* pIndeces, size_t size) { IDirect3DIndexBuffer9* pIndexBuffer; IDirect3DDevice9* pDevice = GetDirect3DDevice(); // 16byte型のインデックスバッファを作成 if( FAILED(pDevice->CreateIndexBuffer(size, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &pIndexBuffer, NULL)) ) { return NULL; } void* pData; // バッファをロックしてデータを書き込む if( SUCCEEDED(pIndexBuffer->Lock(0, size, &pData, 0)) ) { memcpy(pData, pIndeces, size); pIndexBuffer->Unlock(); } return pIndexBuffer; }
頂点バッファの生成とかなり似ているのが分るかと思います。
基本的にDirectXのバッファは似た振る舞いで作成できるようになっているので流れは基本的に似通っています。
pDevice->CreateIndexBuffer(size, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &pIndexBuffer, NULL)
引数の内容も大体頂点バッファと同じようなものです。
異なる箇所としては第三引数のD3DFMT_INDEX16の部分です。
D3DFMT_INDEX16はインデックスバッファのフォーマットを指定しています。
D3DFMT_INDEX16を指定した場合はインデックスバッファは16bit(2byte)になります。
16bitで足りない場合はD3DFMT_INDEX32を指定することで32bit(4byte)まで利用できます。
16bitは65535個までの数値を扱えるのでそれなりのクオリティのモデルであれば問題なく作れるかと思います。
次に先ほどの生成処理をインデックスバッファを含めた形に修正します。
IDirect3DVertexBuffer9* g_pVertexBuffer; IDirect3DIndexBuffer9* g_pIndexBuffer; // リソースの初期化 bool InitializeResource(void) { const SimpleVertex vertices[8] = { // 1つ目の矩形 { 10.0f, 10.0f, 0.0f, 1.0f, 0xffff7f7f }, { 50.0f, 10.0f, 0.0f, 1.0f, 0xff7fff7f }, { 10.0f, 50.0f, 0.0f, 1.0f, 0xff7f7fff }, { 50.0f, 50.0f, 0.0f, 1.0f, 0xffffffff }, // 2つ目の矩形 { 110.0f, 110.0f, 0.0f, 1.0f, 0xffff7f7f }, { 150.0f, 110.0f, 0.0f, 1.0f, 0xff7fff7f }, { 110.0f, 150.0f, 0.0f, 1.0f, 0xff7f7fff }, { 150.0f, 150.0f, 0.0f, 1.0f, 0xffffffff }, }; // 頂点バッファの生成 g_pVertexBuffer = CreateVertexBuffer(vertices, sizeof(vertices)); if( g_pVertexBuffer == NULL ){ return false; } const UINT16 indices[12] = { 0, 1, 2, 2, 1, 3, // 1つ目の矩形 4, 5, 6, 6, 5, 7, // 2つ目の矩形 }; // インデックスバッファの生成 g_pIndexBuffer = CreateIndexBuffer(indices, sizeof(indices)); if( g_pIndexBuffer == NULL ){ return false; } return true; } // リソースの解放 void CleanupResource(void) { SAFE_RELEASE(g_pVertexBuffer); SAFE_RELEASE(g_pIndexBuffer); }
頂点バッファは12個から8個に減りました。
その代わりにインデックスバッファが12個分用意してあります。
これを見てインデックスバッファがどういった役割か分かった方もいるかと思います。
インデックスバッファとは重複した頂点バッファを作らないように使用する頂点バッファを番号(インデックス)で管理するための物です。
頂点バッファには様々な情報が入っているのでデータサイズが大きくなることがあります。
なのでインデックスバッファを使用して削減した方が全体のデータ量が少なくて済むのです。
// インデックスバッファの設定 pDevice->SetIndices(g_pIndexBuffer); // 頂点バッファの設定 pDevice->SetStreamSource(0, g_pVertexBuffer, 0, sizeof(SimpleVertex)); // 描画 pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 4);
今度はDrawPrimitiveをDrawIndexedPrimitiveに変更します。
そしてDrawコールを呼び出す前に使用するインデックスバッファの設定を追加しています。
インデックスバッファを使った描画も変更はこれだけです。
実際に実行してみるとこうなります。
矩形が思ったところに2つ出ました。
これが出来れば複雑なモデルだとしても基本の流れはこの処理なので描画することができるようになります。
ただこのままでは指定した色の矩形が出るだけで絵が出せていません。
次の記事では画面に事前に用意した絵を表示するための方法を記載していきたいと思います。