IndexBufferによるポリゴン描画
-DirectX9編-


概要

インデックスバッファは頂点バッファのインデックスを保存しているバッファです。
このバッファの要素1つで1つのポリゴンを構成しており、
要素には3つ以上の整数が保存されています。

インデックスバッファは3Dモデルデータにはほぼ含まれている情報なので、
ObjファイルやFBXなどの3Dモデルを描画する場合は
インデックスバッファによる描画の方法を知っておく必要があります。
(XFileの場合、DirectX9ではサポートがされています)

サンプル

サンプルはここからダウンロードでき、環境については以下の内容となっています。

開発環境
VSのバージョン VisualStudio 2019
DirectXのバージョン DirectX9

VertexBuffer

VertexBufferを描画で使用できるようにするには
「VertexBufferの作成」と「頂点情報の保存」を行う必要があります。

VertexBufferの作成

VertexBufferの作成はIDirect3DDevice9の「CreateVertexBuffer」を使用します。

directx_0043
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などの特別なメモリで領域確保を行われているので、
簡単にアクセスできないようになっています。

directx_0044
directx_0045
// 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」を使用します。

directx_0046
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で使用されます。

directx_0047
// 頂点バッファの登録
g_D3DDevice->SetStreamSource(0, model->m_VertexBuffer, 0, custom_vertex_size);

SetIndices

SetIndicesはIDirect3DDevice9が持つ関数で、
描画に使用するIndexBufferを登録することができます。
この関数で登録されたIndexBufferがDrawIndexedPrimitiveで使用されます。

directx_0048
// インデックスバッファの登録
g_D3DDevice->SetIndices(model->m_IndexBuffer);

DrawIndexedPrimitive

DrawIndexedPrimitiveはIDirect3DDevice9が持つ関数で、
実行までに登録されているVertexBufferやIndexBufferなどの
情報を使用してポリゴンを描画します。

directx_0049
BaseVertexIndexとMinVertexIndex、NumVerticesはVertexBufferの指定、
startIndexとprimCountはIndexBufferの指定を行っています。

// 描画
g_D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, model->m_VertexNum, 0, model->m_FaceNum);

これでIndexBufferによる描画は完了です。

directx_0050