IndexBufferによるポリゴン描画
-DirectX9編-
概要
インデックスバッファは頂点バッファのインデックスを保存しているバッファです。
このバッファの要素1つで1つのポリゴンを構成しており、
要素には3つ以上の整数が保存されています。
インデックスバッファは3Dモデルデータにはほぼ含まれている情報なので、
ObjファイルやFBXなどの3Dモデルを描画する場合は
インデックスバッファによる描画の方法を知っておく必要があります。
(XFileの場合、DirectX9ではサポートがされています)
サンプル
サンプルはここからダウンロードでき、環境については以下の内容となっています。
開発環境
VSのバージョン |
VisualStudio 2019 |
DirectXのバージョン |
DirectX9 |
VertexBuffer
VertexBufferを描画で使用できるようにするには
「VertexBufferの作成」と「頂点情報の保存」を行う必要があります。
VertexBufferの作成
VertexBufferの作成はIDirect3DDevice9の「CreateVertexBuffer」を使用します。
if (FAILED(g_D3DDevice->CreateVertexBuffer(
// 作成するバッファのサイズ(頂点バッファの数 * 頂点構造体のサイズ)
model_size,
// 使用方法
0,
// FVF設定(SetFVF設定できるので0でも可)
0,
// メモリの指定
D3DPOOL_MANAGED,
// 生成したVertexBufferの格納先の指定
&model->m_VertexBuffer,
// nullptr固定
nullptr)))
{
return false;
}
頂点情報の保存
作成された頂点バッファは何も保存されていないので、
3Dモデルなどの描画を行いたい頂点情報を保存します。
VertexBufferへのアクセスはIDirect3DVertexBuffer9の「Lock」「Unlock」を使います。
この二つの関数はセットになっているのでLockしたらUnlockを忘れないでください。
なぜ、このような方法をとらなければいけないかというと、
VertexBufferはVRAMなどの特別なメモリで領域確保を行われているので、
簡単にアクセスできないようになっています。
// VertexBufferにデータをコピーする
MeshVertex* list;
if (SUCCEEDED(g_CubeMesh.m_VertexBuffer->Lock(
// Lockする領域のオフセット値
0,
// Lockする領域のサイズ(0なら全体)
0,
// ロックされたポインタ変数を受け取る変数
(void**)&list,
// ロックの種類
0
)))
{
for (int i = 0; i < g_CubeMesh.m_VertexNum; i++)
{
list[i] = g_CubeMesh.m_VertexList[i];
}
g_CubeMesh.m_VertexBuffer->Unlock();
return true;
}
IndexBuffer
IndexBufferを描画で使用できるようにするには「IndexBufferの作成」と
「インデックス情報の保存」を行う必要があります。
IndexBufferの作成
IndexBufferの作成はIDirect3DDevice9の「CreateIndexBuffer」を使用します。
if (FAILED(g_D3DDevice->CreateIndexBuffer(
// インデックスバッファのサイズ
buffer_size,
// 使用方法
D3DUSAGE_WRITEONLY,
// インデックスバッファのフォーマット
D3DFMT_INDEX16,
// メモリの指定
D3DPOOL_MANAGED,
// 生成したIndexBufferの格納先の指定
&model->m_IndexBuffer,
// nullptr固定
nullptr)))
{
return false;
}
インデックス情報の保存
作成されたバッファは何も保存されていないので、
VertexBufferのインデックスを保存します。
VertexBuffer上のどのインデックスでポリゴンを構成するかは
3Dモデルデータに含まれています。
IndexBufferへのアクセスはVertexBufferと同様にIDirect3DIndexBuffer9の
「Lock」「Unlock」を使います。
もう一度書きますが、この二つの関数はセットになっているので
LockしたらUnlockを忘れないでください。
※Lock、Unlockの関数の内容はVertexBufferと変わらないので省略します。
WORD* index_buffer;
if (SUCCEEDED(g_CubeMesh.m_IndexBuffer->Lock(0, 0, (void**)& index_buffer, 0)))
{
for (int i = 0; i < g_CubeMesh.m_FaceNum; i++)
{
for (int j = 0; j < 3; j++)
{
index_buffer[i * 3 + j] = g_CubeMesh.m_IndexList[i * 3 + j];
}
}
g_CubeMesh.m_IndexBuffer->Unlock();
return true;
}
これで、描画のための準備は整いました。
描画
IndexBufferを使用して描画するために最低限実行しなければいけない関数は
「SetStreamSource」「SetIndices」「DrawIndexedPrimitive」です。
描画内容によっては「SetFVF」や「SetMaterial」「SetTexture」などを
実行する必要があります。
SetStreamSource
SetStreamSourceはIDirect3DDevice9が持つ関数で、
描画に使用するVertexBufferを登録することができます。
この関数で登録されたVertexBufferがDrawPrimitiveや
DrawIndexedPrimitiveで使用されます。
// 頂点バッファの登録
g_D3DDevice->SetStreamSource(0, model->m_VertexBuffer, 0, custom_vertex_size);
SetIndices
SetIndicesはIDirect3DDevice9が持つ関数で、
描画に使用するIndexBufferを登録することができます。
この関数で登録されたIndexBufferがDrawIndexedPrimitiveで使用されます。
// インデックスバッファの登録
g_D3DDevice->SetIndices(model->m_IndexBuffer);
DrawIndexedPrimitive
DrawIndexedPrimitiveはIDirect3DDevice9が持つ関数で、
実行までに登録されているVertexBufferやIndexBufferなどの
情報を使用してポリゴンを描画します。
BaseVertexIndexとMinVertexIndex、NumVerticesはVertexBufferの指定、
startIndexとprimCountはIndexBufferの指定を行っています。
// 描画
g_D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, model->m_VertexNum, 0, model->m_FaceNum);
これでIndexBufferによる描画は完了です。