Skip to main content

GPUリソースを作っていく!→ Draw関数

🎮 GPUリソースを作るってどういうこと?

💡まずはイメージ!

  • 「頂点の情報(場所や高さなど)」を作るだけでは、画面に出せません。
  • 作った情報を GPU に渡して、「これを描いて!」とお願いしないといけません。

そのために、**「バッファ」**という入れ物を作って、GPUに渡す必要があります。


📦 GPUに送るデータは2つある!

名前

説明

頂点バッファ

点(場所・高さ・向き・UV)の情報

インデックスバッファ

どの点とどの点をつないで三角形にするか


🧪 具体的にどうやるの?

🎯 頂点バッファを作る部分(簡略)

D3D11_BUFFER_DESC vbDesc = {};
vbDesc.Usage = D3D11_USAGE_DEFAULT; // 普通の使い方
vbDesc.ByteWidth = sizeof(Vertex) * vertices_.size(); // 頂点のサイズぶん
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; // 頂点バッファだよ!

D3D11_SUBRESOURCE_DATA vbData = {};
vbData.pSysMem = vertices_.data(); // これが中身!

device->CreateBuffer(&vbDesc, &vbData, &vertexBuffer_);

🔺 インデックスバッファも同じ感じ

D3D11_BUFFER_DESC ibDesc = {};
ibDesc.Usage = D3D11_USAGE_DEFAULT;
ibDesc.ByteWidth = sizeof(uint32_t) * indices_.size();
ibDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;

D3D11_SUBRESOURCE_DATA ibData = {};
ibData.pSysMem = indices_.data();

device->CreateBuffer(&ibDesc, &ibData, &indexBuffer_);

🔧 わかりやすく言うと…

  1. vbDescibDesc に「バッファの情報(サイズとか)」を伝える
  2. vbDataibData に「実際の中身(点のデータなど)」を入れる
  3. CreateBuffer() で「バッファを作ってGPUに渡す」!

🖼️ 絵にすると…

[CPU]                      [GPU]
 vertices_ ───────▶ 頂点バッファ ┐
                               │→ 画面に表示!
 indices_  ───────▶ 三角形順バッファ┘

🧼 古いバッファはちゃんと片付けよう!

if (vertexBuffer_) vertexBuffer_->Release();
if (indexBuffer_) indexBuffer_->Release();

これは「前のバッファがまだ残ってたら、片付けてから作ろうね!」というお片付けの処理です。

🧊Simple3Dシェーダを使ってレンダリングする

Simple3Dシェーダへの入力に合わせた、インプットレイアウトと(頂点の構造体)と、毎フレーム変更される情報を送るためのコンスタントバッファを作ります。

🎨 1. 頂点の並び順(インプットレイアウト)

💡 そもそも「インプットレイアウト」ってなに?

GPUは「1つの頂点に何が入ってるのか」を知らないと、正しく使えません。
そこで「この順番でデータが入ってるよ!」と教えるための設定が、インプットレイアウトです。


👇 このコードがその設定:

D3D11_INPUT_ELEMENT_DESC layout[] = {
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },   // 座標(x, y, z)
	{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },  // 法線(x, y, z)
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },  // UV座標(u, v)
};

📦 つまり1頂点はこう:

バイト位置

内容

サイズ

0〜11

Position

12バイト (

float x,y,z

)

12〜23

Normal

12バイト (

float x,y,z

)

24〜31

UV

8バイト (

float u,v

)

これを CreateInputLayout() でGPUに登録して、「これに従って読み込んでね」と指示します。


💡 2. 定数バッファ(CBGlobal)

🎒 頂点シェーダに渡す「カメラや光の情報」

描画時に使いたい「世界の情報(カメラ、ライティング、マトリクスなど)」は、毎フレーム変わるので、定数バッファにまとめて送ります。


CBGlobal 構造体の中身

struct CBGlobal {
    XMMATRIX g_matWVP;         // モデル→ビュー→プロジェクションの行列(最終位置)
    XMMATRIX g_matNormalTrans; // 法線用の変換行列
    XMMATRIX g_matWorld;       // モデルのワールド変換
    XMFLOAT4 g_vecLightDir;    // 光の向き
    XMFLOAT4 g_vecDiffuse;     // 拡散光の色
    XMFLOAT4 g_vecAmbient;     // 環境光の色
    XMFLOAT4 g_vecSpeculer;    // 鏡面反射の色
    XMFLOAT4 g_vecCameraPosition; // カメラの位置
    float g_shuniness;         // 鏡面反射の強さ
    BOOL g_isTexture;          // テクスチャありかなしか(フラグ)
    float pad[2];              // 16バイトにそろえるためのパディング
};

🔧 どう使われるの?

描画のときに、C++ 側で値をセットして GPU に送ります:

Direct3D::pContext_->UpdateSubresource(globalCB, 0, nullptr, &cb, 0, 0);
Direct3D::pContext_->VSSetConstantBuffers(0, 1, &globalCB);
Direct3D::pContext_->PSSetConstantBuffers(0, 1, &globalCB);

このようにすると、HLSLのシェーダー側で次のように受け取れます:

cbuffer CBGlobal : register(b0)
{
    float4x4 g_matWVP;
    float4x4 g_matNormalTrans;
    float4x4 g_matWorld;
    float4 g_vecLightDir;
    ...
}

💫 最後にまとめると

パーツ名

役割

インプットレイアウト

頂点が「どういう順番で並んでるか」をGPUに教える

CBGlobal構造体

カメラ・光・変換マトリクスなど、描画に必要な「毎回変わる情報」をまとめる

🖼️ Draw関数を作って描画していく

地形(Terrain)が画面に出るようにする!
基本は、今までやったQuadクラスとかの描画と一緒。


🪜 ステップで説明


✅ ① 頂点バッファとインデックスバッファをGPUに渡しておく(もうやった)

これは CreateBuffers() の中でやりました。
「地形の形(点と三角形)」を GPU に教えてある状態です。


✅ ② シェーダーの準備(もうやった)

  • 頂点シェーダ(VS)
  • ピクセルシェーダ(PS)
  • 入力レイアウト(頂点データの並び方)

これは InitShaderBundle() で設定済みです。


🆕 ③ 定数バッファにデータを入れて送る

CBGlobal に、プレイヤーの位置・カメラ・光の向きなどを詰めて送ります。

CBGlobal cb = {};
cb.g_matWVP = ...; // カメラを使った行列を計算して代入
cb.g_vecLightDir = { 0, -1, 1, 0 }; // 斜め上から光
...
context->UpdateSubresource(globalCB, 0, nullptr, &cb, 0, 0);
context->VSSetConstantBuffers(0, 1, &globalCB);
context->PSSetConstantBuffers(0, 1, &globalCB);

🆕 ④ GPU に地形データをセットする

地形の「点の情報」や「三角形のつなぎ方」を GPU に渡します。

UINT stride = sizeof(Vertex); // 1つの頂点の大きさ
UINT offset = 0;
context->IASetVertexBuffers(0, 1, &vertexBuffer_, &stride, &offset);
context->IASetIndexBuffer(indexBuffer_, DXGI_FORMAT_R32_UINT, 0);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 三角形で描くよ!

🆕 ⑤ テクスチャをGPUに渡す(画像つきの場合)

ID3D11ShaderResourceView* srv = texture_->GetSRV();
context->PSSetShaderResources(0, 1, &srv);

🆕 ⑥ 実際に描く命令を出す!

ここで「GPUよ!描けー!」と命令します。

context->DrawIndexed(static_cast<UINT>(indices_.size()), 0, 0);

これで、GPUが全部の三角形を使って地形を画面に出します。


✅ 最終的な Draw() の形

void Terrain::Draw(Transform& t)
{
    // ① 定数バッファを埋める
    CBGlobal cb = {};
    cb.g_matWVP = ...;
    ...
    context->UpdateSubresource(globalCB, 0, nullptr, &cb, 0, 0);
    context->VSSetConstantBuffers(0, 1, &globalCB);
    context->PSSetConstantBuffers(0, 1, &globalCB);

    // ② シェーダーを使う
    Direct3D::SetShader(Direct3D::SHADER_3D);

    // ③ 頂点とインデックスを渡す
    context->IASetVertexBuffers(...);
    context->IASetIndexBuffer(...);
    context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // ④ テクスチャを渡す
    context->PSSetShaderResources(0, 1, &texture_->GetSRV());

    // ⑤ 描画命令
    context->DrawIndexed(static_cast<UINT>(indices_.size()), 0, 0);
}

🎉 まとめ

ステップ

やること

状態

① 頂点を作る

MakeTerrain()

などで作成済み


② バッファ作る

CreateBuffers()

済み


③ シェーダーセット

InitShaderBundle()

済み


④ 定数バッファに情報入れる

Draw()

内でやる


⑤ 頂点・インデックス・テクスチャを渡す

Draw()

内でやる


⑥ 描画命令を出す

Draw()

内でやる