今回はDirectX11での頂点バッファとインデックスバッファの作り方について記載していきます。
頂点バッファとインデックスバッファの意味合いについてはDirectX9と同等です。
なのでこの記事ではバッファの作り方をメインに記述していきます。
DirectX11では固定パイプラインが廃止されたので描画はShaderの記事を書いてからになります。
実装部分には前回の初期化の続きになるので、DirectX11クラスなどはそちらの記事をご確認ください!
では早速みていきましょう!
頂点バッファ
DirectX9の記事にも書いていますが頂点バッファとは頂点情報の塊のことです。
頂点バッファで管理する情報には以下のようなものがあります。
座標 | ポリゴンを表示する座標を設定できます。 |
---|---|
法線 | 法線の向き(ライトが影響する向き)を設定できます。 |
カラー | 頂点に色を設定できます。 |
テクスチャ―UV | テクスチャ―を張り付けるUV値を設定できます。 |
影響するボーン | 頂点にアニメーションを付ける際に影響するボーンを設定できます。 |
ウェイト | 各ボーンに対する影響度を設定できます。 |
よく使用するところを記載しましたが、
頂点バッファには他にもいろいろな情報を持たせることができます。
逆に座標だけなどで使用することもできます。
これらの情報を扱いシェーダ―でモデルの形状や質感を出していきます。
では頂点バッファのデータを管理するクラスの実装を見ていきましょう。
VertexBuffer.h
#pragma once #include "DirectX11.h" // VertexBufferクラス class VertexBuffer { public: VertexBuffer(void); ~VertexBuffer(void); // 初期化 bool Initialize(DirectX11& directX, UINT size, void* pInitData); // 終了処理 void Finalize(void); public: // バッファの取得 ID3D11Buffer* GetBuffer(void) { return m_pBuffer; } private: ID3D11Buffer* m_pBuffer; // バッファ };
必要な機能は単純です。
DirectX11でのバッファを管理するID3D11Bufferを初期化・解放する機能。
そしてバッファを取得できるようにしているだけです。
DirectX11では様々なバッファがID3D11Bufferで管理されています。
後で出てくるインデックスバッファも同様です。
このバッファを使って頂点バッファを作成する処理を記述していきます。
VertexBuffer.cpp
#include "VertexBuffer.h" VertexBuffer::VertexBuffer() { m_pBuffer = NULL; } VertexBuffer::~VertexBuffer(void) { Finalize(); } bool VertexBuffer::Initialize(DirectX11& directX11, UINT size, void* pInitData) { auto pDevice = directX11.GetDevice(); D3D11_BUFFER_DESC desc; // 頂点バッファの初期化設定 desc.ByteWidth = size; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; desc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA data; // 初期化時に設定するバッファデータ data.pSysMem = pInitData; data.SysMemPitch = 0; data.SysMemSlicePitch = 0; // 頂点バッファの生成 if (FAILED(pDevice->CreateBuffer(&desc, &data, &m_pBuffer))) { return false; } return true; } void VertexBuffer::Finalize() { SafeRelease(m_pBuffer); }
頂点バッファの作成は単純です。
基本的にはD3D11_BUFFER_DESCのBindFlagsにD3D11_BIND_VERTEX_BUFFERを指定するだけです。
他には頂点バッファのサイズやCPUからのアクセスできるようにするかの設定があります。
これらの設定を元に頂点バッファの生成が行われます。
次にD3D11_SUBRESOURCE_DATAで初期化時に頂点バッファの内容を書き込むことができます。
pSysMemに指定されたデータがバッファにコピーされます。
最後にそれらの設定を使ってID3D11DeviceからCreateBufferを呼び出すだけです。
短いコードで作れるので意外と簡単に感じたのではないでしょうか?
初期化に必要な設定
前項では初期化の実装を記述しました。
このページでは初期化で使用した設定や関数の説明を記述していきます。
D3D11_BUFFER_DESC
ByteWidth | バッファのサイズです。 |
---|---|
Usage | バッファの読み込みや書き込みに関する使用用途を指定します。 最初にデータを書き込むだけであればD3D11_USAGE_DEFAULTで問題ありません。 |
BindFlags | 描画パイプライン上のどこでバインドするかを設定します。 今回は頂点バッファなのでD3D11_BIND_VERTEX_BUFFERを指定します。 |
CPUAccessFlags | CPUに対して許可するアクセス方法を設定できます。 特にCPUからアクセスしないのであれば0で問題ありません。 |
MiscFlags | リソースに対して特殊な設定が必要な場合に使用します。 基本的に0で問題ありません。 |
StructureByteStride | 構造化バッファーを表す場合のサイズです。 基本的に0を指定します。 公式の説明を読んでもよく分からないかと思います。 これはコンピュートシェーダで使用するStructureBuffer(GPUで使用する配列)を使用する際に指定します。 |
バッファの初期化に使用する設定はこれらの設定で行います。
基本的にはBindFlags以外は今回は重要ではありません。
CPU上でのバッファの操作などが出てきた際には他の設定も重要になってきますが…。
D3D11_SUBRESOURCE_DATA
pSysMem | 書き込むデータの先頭アドレス |
---|---|
SysMemPitch | これはテクスチャーでのみ使用します。 |
SysMemSlicePitch | こちらは3Dテクスチャ―でのみ使用します。 |
初期化時に書き込むバッファの指定はこのデータで行います。
テクスチャ―以外ではpSysMemのみ使用されます。
単純に書き込むデータのアドレスを渡すだけなので難しい設定はありません。
ID3D11Device::CreateBuffer
pDesc | 初期化する設定情報です。 |
---|---|
pInitialData | 初期化時に書き込むバッファです。 UsageがD3D11_USAGE_IMMUTABLE以外の場合はNULLも指定できます。 |
ppBuffer | 生成したID3D11Bufferの格納アドレスです。 |
初期化する情報が揃えばあとは初期化処理を呼び出すだけです!
基本的に設定を渡すだけなので特筆すべき点はありません。
これだけで頂点バッファの初期化が出来てしまいます。
DirectX以外の環境でも似たような実装なので流れさえ理解してしまえばすぐに実装できるかと思います。
インデックスバッファ
インデックスバッファも頂点バッファと流れや実装が殆ど同じです。
なので早速実装についてみていきましょう。
IndexBuffer.h
#pragma once #include "DirectX11.h" // IndexBufferクラス class IndexBuffer { public: IndexBuffer(void); ~IndexBuffer(void); // 初期化 bool Initialize(DirectX11& directX, UINT size, void* pInitData); // 終了処理 void Finalize(void); public: // バッファの取得 ID3D11Buffer* GetBuffer(void) { return m_pBuffer; } private: ID3D11Buffer* m_pBuffer; // バッファ };
インデックスバッファも名前が変わっただけで頂点バッファと同じです。
なのでベースとなるBufferクラスを作成して継承により個別に初期化処理を実装することも多いです。
IndexBuffer.cpp
#include "IndexBuffer.h" IndexBuffer::IndexBuffer() { m_pBuffer = NULL; } IndexBuffer::~IndexBuffer(void) { Finalize(); } bool IndexBuffer::Initialize(DirectX11& directX11, UINT size, void* pInitData) { auto pDevice = directX11.GetDevice(); D3D11_BUFFER_DESC desc; // 頂点バッファの初期化設定 desc.ByteWidth = size; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_INDEX_BUFFER; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; desc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA data; // 初期化時に設定するバッファデータ data.pSysMem = pInitData; data.SysMemPitch = 0; data.SysMemSlicePitch = 0; // 頂点バッファの生成 if (FAILED(pDevice->CreateBuffer(&desc, &data, &m_pBuffer))) { return false; } return true; } void IndexBuffer::Finalize() { SafeRelease(m_pBuffer); }
こちらも殆ど実装は同じですね!
今回の実装で違う部分は一か所だけです。
D3D11_BUFFER_DESCのBindFlagsに指定している設定がD3D11_BIND_INDEX_BUFFERになっています。
これで描画パイプライン上のインデックスバッファとして初期化が行われます。
後は全て同じです。
必要に応じて固有の実装をしていくこともありますが、単純に使用するだけであれば特に必要ありません。
初めてDirectX11を触ると難しいと感じる人も多いのですが、使用するだけなら意外と難しい処理は多くないので興味を持ったら描画まで実装を進めてみましょう!
では次回の記事ではDirectX11での描画に必須のシェーダ―について記述していきます。