座標変換
◇行列とベクトルの乗算
ベクトルに行列を乗算すると、別の空間に変換することが出来るので、頂点座標変換は、行列とベクトルの乗算で表現できる。
ゲームをスクリーンに表示するには、3つの行列が必要になる
- ワールド行列
- カメラ行列
- 透視変換行列
学習書籍では、変換行列の詳細な部分については学べないので、「DirectX12の魔導書」を参考に学習します。
◇行列はCPUで作るべきかGPUで作るか?
行列を作るのは、CPU。ワールド行列を作るためのキャラクター座標、カメラ行列をつくるためのカメラ位置、注視点の位置などの情報はCPUがアクセスできるメインメモリ状に存在しています。また、行列と頂点の乗算の計算を比べると、行列を作成するための計算回数はそこまで多くないです。
処理の名前 | 計算回数 | 計算するプロセッサ |
---|---|---|
ワールド行列の作成 | 1キャラにつき数回 | CPU |
カメラ行列の作成 | 1キャラにつき数回 | CPU |
透視変換行列の作成 | 1キャラにつき数回 | CPU |
頂点座標とワールド行列の乗算 | 1キャラにつき10000回以上 | GPU |
頂点座標とカメラ行列の乗算 | 1キャラにつき10000回以上 | GPU |
頂点座標と透視変換行列の乗算 | 1キャラにつき10000回以上 | GPU |
上記の表を見るように、行列の作成は数回程度であり、それほど多くない。
◇メモリの転送
CPUで計算したデータをGPUに送る必要がある。これらの仕組みについて学習をしていく。
■定数バッファー
定数バッファーは、「シェーダー内で参照する読み取り専用の値をまとめておく場所」
CPUが書き込み、GPUが読み取る流れ。
ワールド行列、カメラ行列、透視変換行列の計算をする。
↓
計算した結果をグラフィックスメモリにコピーをする。
■ディスクリプタヒープ
定数バッファーは、作成しただけではGPUでは使用することが出来ない。頂点バッファーやインデックスバッファーと同じように、使用する前に適切な設定を行う必要がある。DirectX12では、定数バッファーやテクスチャなどをまとめて設定するためのディスクリプタヒープというものが用意されている。
実践 ワールド行列を作成して三角形を動かす
今回は、コードについて説明はしませんが、このような流れで処理を実装をしていきます。
■C++での実装処理
- 定数バッファーの作成
- ディスクリプタヒープの作成
- ワールド行列の作成
- ワールド行列を定数バッファにコピー
- ディスクリプタヒープを設定です。
// (省略:初期化処理)
// step-1 定数バッファを作成
ConstantBuffer cb;
cb.Init(sizeof(Matrix));
// step-2 ディスクリプタヒープを作成
DescriptorHeap descHeap;
descHeap.RegistConstantBuffer(0, cb);
descHeap.Commit();
// ゲームループ
while (DispatchWindowMessage())
{
g_engine->BeginFrame();
// step-3 ワールド行列を作成
Matrix mWorld;
mWorld.MakeTranslation(0.5f, 0.4f, 0.0f);
// step-4 ワールド行列をグラフィックメモリにコピー
cb.CopyToVRAM(mWorld);
// step-5 ディスクリプタヒープを設定
renderContext.SetDescriptorHeap(descHeap);
//三角形をドロー
triangle.Draw(renderContext);
}
■HLSL側での実装
// step-6 レジスタb0のデータにアクセスするための変数を定義する
float4x4 g_WorldMatrix : register(b0);
VSOutput VSMain(VSInput In)
{
VSOutput vsOut = (VSOutput)0;
vsOut.pos = mul(g_WorldMatrix, In.pos);
vsOut.color = In.color;
return vsOut;
}
これで、CPUから定数バッファーとディスクリプタヒープを用いてHLSL側にデータを渡すことが出来ました。
テクスチャマッピング
◇テクスチャとは
テクスチャとは、多くの場合3Dモデルの模様を表す画像データのこと。
参考:
◇UV座標
テクスチャを張り付けるときは、UV座標というものを使う。
右下を(1,1)として、横方向をU、縦方向をVとして表すことから、UV座標という。
テクスチャをモデルに張り付けるときに、このUV座標を参考に、塗るべき色を決定していく。
実践 三角形ポリゴンにテクスチャを貼り付ける
◇C++での実装
// step-1 三角形ポリゴンにUV座標を設定
triangle.SetUVCoord(0, 0.0f, 1.0f);
triangle.SetUVCoord(1, 0.5f, 0.0f);
triangle.SetUVCoord(2, 1.0f, 1.0f);
// step-2 テクスチャをロード
Texture texture;
texture.InitFromDDSFile(L"Assets/image/sample_00.dds");
// ディスクリプタヒープを作成
DescriptorHeap ds;
ds.RegistConstantBuffer(0, cb);
// step-3 テクスチャをディスクリプタヒープに登録
ds.RegistShaderResource(0, texture);
テクスチャを読み込むときは、ワールド行列の値をGPUに送るためにディスクリプタヒープと定数バッファーに値を渡す流れは同じです。
新たに追加されたのが、UV座標の登録処理と、テクスチャの登録処理です。
◇HLSLでの実装
sampler g_sampler : register(s0);
Texture2D g_texture : register(t0);
float4 PSMain(VSOutput vsOut) : SV_Target0
{
// step-5 テクスチャカラーをサンプリングして返す
float4 texcolor = g_texture.Sample(g_sampler, vsOut.uv);
return texcolor;
}
複雑な3Dモデルの表示
ここまで、シンプルな三角形ポリゴンの表示を例に、シェーダーの基礎を学ぶことが出来ました。
三角形ポリゴンを表示するために、次の3つの情報が必要です。
- 頂点バッファー
- インデックスバッファー
- テクスチャ
複雑なモデルの描画も、この三角形ポリゴンの表示の知識で行うことが出来る。
まとめ
今回は、CPUからGPUにデータを送るための定数バッファーとディスクリプターとシェーダー側での設定方法を使った処理の作成方法と、テクスチャデータをGPUに送り、ポリゴンに適用させる方法について学ぶことが出来ました。
この処理は、モデルデータでも適用できるのでこの基本的な処理の流れを頭に入れるようにし、次回のライティング学習に臨んでいきます。