
マイケル
みなさんこんにちは!
マイケルです!
マイケルです!

エレキベア
こんにちクマ〜〜〜

マイケル
突然ですが、今回から何回かに分けて
DirectX12 を触っていこうと思います!
DirectX12 を触っていこうと思います!

エレキベア
ついに触る時が来たクマか・・・

マイケル
というのも、描画周りの学習を進めていくにあたり
やはり描画パイプライン周りの知識は必要だな、と感じたためです。
やはり描画パイプライン周りの知識は必要だな、と感じたためです。

エレキベア
前OpenGLで簡単なゲームも作ってたクマが、
拡張ライブラリやSDLも使用してたクマからね〜〜
拡張ライブラリやSDLも使用してたクマからね〜〜

【C++】第五回 C++を使ったゲーム開発 〜OpenGLを使った3Dゲーム開発編〜
マイケルみなさんこんばんは!マイケルです!エレキベアクマ〜〜〜〜!!マイケルさあC++ゲーム開発シリーズもついに第五回!いよいよ3Dゲームを作ります!!↑前回の記事エレキ...
↑以前OpenGLで作ったゲーム

マイケル
あとはやっぱり一度は触ってみたかったからね!!
今回は下記のように画面の塗りつぶしと四角形のポリゴン表示を行うサンプルを作っていこうと思います!
今回は下記のように画面の塗りつぶしと四角形のポリゴン表示を行うサンプルを作っていこうと思います!

エレキベア
こんなの余裕クマ〜〜〜

マイケル
それでもこれだけで300行以上のコードを書くことになるんだよね・・・
しかし一つ一つ見ていけば絶対に理解できるので、諦めずにやっていきましょう!
しかし一つ一つ見ていけば絶対に理解できるので、諦めずにやっていきましょう!

エレキベア
これだけでそんなに書くクマか・・・

マイケル
今回作ったサンプルについては下記GitHubのリポジトリに上げていますので
こちらもご参照ください!
こちらもご参照ください!
GitHub – masarito617/cpp-dx12-sample-polygon
↑今回作ったサンプル

マイケル
下記のように公式のサンプルやチュートリアルもあるのですが、正直知識0からこれを理解していくのはかなり苦難なのではないかと思いました・・・。
実用的なサンプル – Win32 apps | Microsoft Learn
GitHub – microsoft / DirectX-Graphics-Samples
↑公式のサンプル、チュートリアル

エレキベア
ワケが分からないクマ〜〜〜

マイケル
そのため今回は下記の参考書も参考にさせてもらいつつ、なるべくチュートリアルのコードと近くなるよう整理して作りました。
この記事と合わせて見ることで、公式のサンプルコードを理解する手助けになればと思います!
この記事と合わせて見ることで、公式のサンプルコードを理解する手助けになればと思います!
DirectX 12の魔導書 3Dレンダリングの基礎からMMDモデルを踊らせるまで

エレキベア
DirectX12の書籍があまりないから本当にありがたいクマね

マイケル
それでは早速やっていこう!!
DirectX12の基礎知識

マイケル
ということでコードを書いていきたい・・・ところですが、
その前に前提知識としてDirectX12の基礎知識について知っておきましょう!
12に至るまでの簡単な歴史とパイプライン、知っておくべき用語について説明します!
その前に前提知識としてDirectX12の基礎知識について知っておきましょう!
12に至るまでの簡単な歴史とパイプライン、知っておくべき用語について説明します!

エレキベア
楽しみクマ〜〜〜
DirextXの歴史とパイプライン

マイケル
まず、DirectXが12に至るまでの歴史についてはざっくりと下記のようになっています。
DirectX9から本格的にHLSL言語でシェーダプログラミングが出来るようになり、そこからシェーダステージの追加やパイプラインの変更が行われていることが分かります。
DirectX9から本格的にHLSL言語でシェーダプログラミングが出来るようになり、そこからシェーダステージの追加やパイプラインの変更が行われていることが分かります。
年代 | バージョン | 概要 |
---|---|---|
1997年〜 | DirectX5 | Windows95の時代になってから普及し、PCで3Dゲームすることを広めた。 |
1998年〜 | DirectX6 | ラスタライズ処理やテクスチャ貼りつけ等のピクセル単位の処理のみ担当した。 |
1999年〜 | DirectX7 | 頂点単位の座標変換、光源処理を担当できるようになった。 |
2000年〜 | DirectX8 | シェーダをプログラムできるプログラマブルシェーダをサポートした。(SM1.x) |
2002年〜 | DirectX9 | SM2.0、SM3.0と対応され、HLSL言語にも対応するようになる。 |
2006年〜 | DirectX10 | SM4.0に対応し、ジオメトリシェーダを含めたパイプラインに変更された。 |
2009年〜 | DirectX11 | SM5.0に対応し、新たに4つのシェーダステージが追加された。 (DirectX9、10と互換性有り) |
2015年〜 | DirectX12 | SM5.1に対応し、Pipeline State Object (PSO)というパイプラインの仕組みに変更された。(DirectX11と互換性無し) |

エレキベア
DirectX12になるまでもいろんな歴史があったクマね

マイケル
DirectX9〜11までのパイプラインの変更内容についてはざっくりと下記のようになっています。

マイケル
「頂点シェーダ」「ピクセルシェーダ」だけだったものが、10で「ジオメトリシェーダ」が追加されています。
また、11ではテッセレーションステージと呼ばれる「ハルシェーダ」「テッセレータ」「ドメインシェーダ」の3つのシェーダステージに加え、図にはありませんが「演算シェーダ(Compute Shader)」と呼ばれる汎用目的でGPUを使用するためのシェーダも追加されています。
また、11ではテッセレーションステージと呼ばれる「ハルシェーダ」「テッセレータ」「ドメインシェーダ」の3つのシェーダステージに加え、図にはありませんが「演算シェーダ(Compute Shader)」と呼ばれる汎用目的でGPUを使用するためのシェーダも追加されています。

エレキベア
こんなに種類があるのクマか・・・

マイケル
バージョンアップに伴い、パイプラインもかなり複雑になっているね・・・
各シェーダの役割は下記のようになっています!
各シェーダの役割は下記のようになっています!
シェーダ名 | 概要 |
---|---|
頂点シェーダ | 頂点単位の陰影処理を行う。 |
ハルシェーダ | ポリゴンの分割レベル、分割手法を決定する。 |
テッセレータ | 渡されたポリゴン分割計画によって分割を行う。(固定機能) |
ドメインシェーダ | 仮想的に分割された各頂点を変異させる。 |
ジオメトリシェーダ | 頂点の増減を行う。 |
ピクセルシェーダ | ピクセル単位の陰影処理を行う。 |
演算シェーダ | GPUで汎用計算を行う。 |

マイケル
とはいえ今回は基本的な「頂点シェーダ」「ピクセルシェーダ」しか使わないので、概要だけ覚えておきましょう!
用語とイメージ

マイケル
パイプラインの流れについてはざっくりとイメージが伝わったかと思いますが、DirectX12ではPipeline State Object (PSO)と呼ばれる仕組みが導入され、効率化のためにある程度まとめてGPUへ渡す方向になっています。

マイケル
それに併せて様々な概念が導入され11より更に複雑になり、専門用語も増えています。
ポリゴン表示までに必要な用語を並べると下記のようになります。
ポリゴン表示までに必要な用語を並べると下記のようになります。
用語 | 概要 |
---|---|
コマンドリスト | GPUへの命令を受け取る。 |
コマンドアロケータ | コマンドリストで受け取った命令を溜め込む。 |
コマンドキュー | コマンドアロケータに溜め込んだ命令を先頭から実行する。 |
ディスクリプタ | GPUに送るリソースの仕様について示したもの。 |
ディスクリプタヒープ | ディスクリプタをまとめたもの。 |
ディスクリプタテーブル | ルートシグネチャ内で設定し、ディスクリプタヒープとシェーダーのレジスタを関連付けたもの。 |
ルートシグネチャ | ディスクリプタテーブルをまとめたもの。 |
パイプラインステートオブジェクト | 表示までに必要なパイプラインのパラメータを1つのオブジェクトにまとめたもの。 |
フェンス | GPUの処理が終わったかどうかを監視するためのもの。 |
バリア | コマンド実行時にリソースが何の用途に使用されるのかをGPUに伝えるもの。 |

エレキベア
うおおうぅ・・・
ポリゴン表示するだけでこんなにクマか・・・
ポリゴン表示するだけでこんなにクマか・・・

マイケル
専門用語が多すぎておおぅ・・・となってしまいますが、これらも大方「まとめる」という思想が元になっていると考えられます。
例えば、下記のようなイメージです。
例えば、下記のようなイメージです。
・GPUへの命令はコマンドリストを通してコマンドアロケータに格納し、コマンドキューから取り出して実行する
・ディスクリプタ(ビューやテクスチャ等の情報)はディスクリプタヒープにまとめてGPUへ渡す

エレキベア
なるほどクマ
用語はややこしいクマが、やっていることはそこまで難しくはないクマね
用語はややこしいクマが、やっていることはそこまで難しくはないクマね

マイケル
とりあえず最低限必要な知識は以上になります!
ここからは実際にコードを書いてイメージを掴んでいきましょう!!
ここからは実際にコードを書いてイメージを掴んでいきましょう!!
Win32APIでのウィンドウ表示

マイケル
それではサンプルを作っていきますが、改めてGitHubのコードは下記になります。
今回はVisualStudio2022を使用しました。
今回はVisualStudio2022を使用しました。
GitHub – masarito617/cpp-dx12-sample-polygon
↑今回作ったサンプル

マイケル
まずはDirectXを触る前に、土台となるウィンドウを作成します。
こちらはWindowsAPI(Win32API)を使用して実装していますが、今回は簡単な説明に留めるので詳細は公式ドキュメントをご参照ください!
こちらはWindowsAPI(Win32API)を使用して実装していますが、今回は簡単な説明に留めるので詳細は公式ドキュメントをご参照ください!
Windows API インデックス | Win32 apps | Microsoft Learn

エレキベア
ウィンドウ表示自体はDirectXは使用しないクマね
空のプロジェクト作成

マイケル
まずは空のプロジェクトを作成します。
今回は cpp-dx12-sample-polygon という名前にしました。
今回は cpp-dx12-sample-polygon という名前にしました。

エレキベア
ここから始まるクマね
ウィンドウを表示する

マイケル
ここからコードを書いていきますが、その前にWindowsAPIを使用するため
リンカー > システム > サブシステム をWindowsに指定しておきます。
リンカー > システム > サブシステム をWindowsに指定しておきます。

マイケル
そして
・Win32Application.h
・Win32Application.cpp
を作成して下記のように記述します。
・Win32Application.h
・Win32Application.cpp
を作成して下記のように記述します。

マイケル
これはウィンドウ表示の処理になりますが、お決まりのような実装になるので覚えてしまいましょう!
あとはmain.cppを作成して下記のように呼び出せばウィンドウ表示は完了です!
あとはmain.cppを作成して下記のように呼び出せばウィンドウ表示は完了です!

エレキベア
ここまでは余裕クマね
画面を特定の色で塗りつぶす

マイケル
ウィンドウの準備が出来たところで、DirectXを使っていきましょう!
ポリゴン表示をする・・・前に、まずは画面を特定の色で塗りつぶすというところまで実装していきます。
ポリゴン表示をする・・・前に、まずは画面を特定の色で塗りつぶすというところまで実装していきます。

エレキベア
それくらいなら余裕クマよ

マイケル
果たしてそんな簡単にいくかな・・・?
じっくり見ていきましょう!
じっくり見ていきましょう!
d3dx12.hの導入

マイケル
コードを書く前に今回はDirectXでよく使用する処理をヘルパー関数として整理してある d3dx12.h を導入します。
こちらはGitHubに公開されているのでダウンロードしてプロジェクト配下に格納しておきましょう。
この後、インクルードして使用していきます。
こちらはGitHubに公開されているのでダウンロードしてプロジェクト配下に格納しておきましょう。
この後、インクルードして使用していきます。
Direct3D 12 のヘルパー構造と関数 – Win32 apps | Microsoft Learn
GitHub – microsoft/DirectX-Headers/blob/main/include/directx/d3dx12.h

マイケル
ヘルパー関数自体は、ほぼコード量を減らすために簡単にまとめただけのものとなっています。
内部でどのようなことを行っているか?も一緒に見ながら進めると理解しやすくなると思います。
内部でどのようなことを行っているか?も一緒に見ながら進めると理解しやすくなると思います。

エレキベア
これを導入しても量はかなり多いクマけどね・・・
大枠を実装

マイケル
それではここから大枠を実装していきます。
・DXApplication.h
・DXApplication.cpp
として作成し、下記のように記述しましょう。
・DXApplication.h
・DXApplication.cpp
として作成し、下記のように記述しましょう。

マイケル
タイトル、ウィンドウサイズといった情報を受け取った後、
・初期化処理 (OnInit)
・更新処理 (OnUpdate)
・描画処理 (OnRender)
・終了処理 (OnDestroy)
といったゲームループの形で用意しています。
・初期化処理 (OnInit)
・更新処理 (OnUpdate)
・描画処理 (OnRender)
・終了処理 (OnDestroy)
といったゲームループの形で用意しています。

マイケル
このクラスをWin32Applicationクラスからも参照、呼び出しするよう修正します。

マイケル
ウィンドウ処理のタイミングに合わせてゲームループの関数を呼び出していることが分かります。
あとはmain.cpp内で初期化して渡せば、大枠は完成です!
あとはmain.cpp内で初期化して渡せば、大枠は完成です!

マイケル
この状態で実行してエラーが発生しないか確認してみましょう。

エレキベア
あとはDirectXの処理を実装していくのみクマね
DirextX12オブジェクトの定義

マイケル
ここからDirectX12に関連するオブジェクトを初期化していきます。
まずはヘッダーファイルを下記のように修正しましょう。
まずはヘッダーファイルを下記のように修正しましょう。

エレキベア
だいぶ増えたクマが冒頭で紹介していた用語のものがほとんどになるクマね

マイケル
軽く内容を見てみよう!
必要なヘッダをインクルード

マイケル
最初にインクルードしているのはDirectXに用意されているヘッダになります。
ライブラリのリンクも必要になるため、忘れずに記述しましょう。
ライブラリのリンクも必要になるため、忘れずに記述しましょう。
ComPtrの使用

マイケル
そしてDirectX関連の変数がComPtrというあまり見慣れない型で定義されていますが、
こちらはstd::shared_ptrと似た働きを持つスマートポインタになります。
こちらはstd::shared_ptrと似た働きを持つスマートポインタになります。
↑ComPtr型で定義されている

マイケル
異なるのは解放時の動きで、参照カウントが0になった際にはRelease関数が呼び出されます。
DirectX関連のオブジェクトはGPUメモリも確保している場合があるため、ComPtrを使用することで明示的にReleaseを記述する必要がなくなる、というわけです!
DirectX関連のオブジェクトはGPUメモリも確保している場合があるため、ComPtrを使用することで明示的にReleaseを記述する必要がなくなる、というわけです!

エレキベア
なるほどクマ
GPU使用を考慮したスマートポインタというわけクマね
GPU使用を考慮したスマートポインタというわけクマね

マイケル
Microsoft::WRL::ComPtrで使用することができますが、長いため下記のように定義しておくと扱いやすくなります。
必要なオブジェクトの定義

マイケル
下記はDirectX関連のオブジェクトで、ほぼComPtrで定義しています。
こちらはこの後初期化処理を記述していきます。
こちらはこの後初期化処理を記述していきます。

エレキベア
やっぱり多いクマね〜〜
DirextX12オブジェクトの初期化

マイケル
それでは実際に初期化処理を記述します。
OnInit、LoadPipeline関数を下記のように実装しましょう!
OnInit、LoadPipeline関数を下記のように実装しましょう!

エレキベア
おおおぅ・・・・

マイケル
ヘルパー関数を使っているのにこの量です・・・
こちらも一つ一つ見ていきましょう!
こちらも一つ一つ見ていきましょう!
初期化時のエラーハンドリング

マイケル
DirectX関連のオブジェクトの結果はHRESULTという形式で返ってきます。
こちらの結果チェックとしてThrowIfFailed関数を用意しました。
公式サンプルのコードを真似たもので、エラーの場合は問答無用でthrowしています。
こちらの結果チェックとしてThrowIfFailed関数を用意しました。
公式サンプルのコードを真似たもので、エラーの場合は問答無用でthrowしています。

エレキベア
ThrowIfFailedで囲んでいる処理はHRESULT形式で返ってくる処理なのクマね
デバイスの初期化

マイケル
まずは基本オブジェクトとなるデバイス(ID3D12Device)オブジェクトを生成します。
流れとしては
・生成に必要となるIDXGIFactory6オブジェクトを生成
・EnumAdapters関数で使用できるアダプタを探す
・生成可能なFEATURE_LEVELを探しつつID3D12Deviceオブジェクトを初期化する
といった流れになっています。
流れとしては
・生成に必要となるIDXGIFactory6オブジェクトを生成
・EnumAdapters関数で使用できるアダプタを探す
・生成可能なFEATURE_LEVELを探しつつID3D12Deviceオブジェクトを初期化する
といった流れになっています。

マイケル
頭でデバッグレイヤーも有効にしていますが、こちらは有効にすることでエラーの詳細まで確認できるようになります。

マイケル
strAdapter.find(L”AMD”)の部分に関しては、自分の環境でAMDのGPUを指定していたために名称からfindしています。
リリースする際には使用できるアダプタを一覧表示して設定画面で選ばせるような対処が必要になるため、ご注意ください。
リリースする際には使用できるアダプタを一覧表示して設定画面で選ばせるような対処が必要になるため、ご注意ください。

エレキベア
環境によって複数GPUが搭載されている場合もあるクマね
コマンド関連のオブジェクト初期化

マイケル
そして次にコマンド関連のオブジェクトを生成しています。
こちらは冒頭で紹介した通り
・コマンドリスト
・コマンドアロケータ
・コマンドキュー
の3つが対処になります。
こちらは冒頭で紹介した通り
・コマンドリスト
・コマンドアロケータ
・コマンドキュー
の3つが対処になります。

エレキベア
どれもデバイスオブジェクトの関数を呼び出して生成しているクマね
スワップチェーンを生成してディスクリプタヒープと紐づける

マイケル
そして次に画面の色を変更するためにスワップチェーンを生成します。
こちらはダブルバッファを行うために必要なもので、
・スワップチェーンオブジェクトを生成
・ディスクリプタヒープを生成
・ディスクリプタヒープとスワップチェーンを関連付けてレンダーターゲットビューを生成
といった流れで実装しています。
こちらはダブルバッファを行うために必要なもので、
・スワップチェーンオブジェクトを生成
・ディスクリプタヒープを生成
・ディスクリプタヒープとスワップチェーンを関連付けてレンダーターゲットビューを生成
といった流れで実装しています。

マイケル
スワップチェーンを行うため、フレーム数(2)分ループしながらレンダーターゲットビュー(RTV)を生成しています。
また冒頭で紹介した通り、ディスクリプタヒープにディスクリプタ(RTV)をまとめる形式になっていることが分かります。
また冒頭で紹介した通り、ディスクリプタヒープにディスクリプタ(RTV)をまとめる形式になっていることが分かります。

エレキベア
少し複雑クマがじっくり見ていけば分かるクマね
フェンスの作成

マイケル
そして最後にGPU処理を待機するためのフェンスオブジェクトを生成しています。
こちらはDestroy時にCloseする必要があるため、そちらも忘れないようにしましょう。
こちらはDestroy時にCloseする必要があるため、そちらも忘れないようにしましょう。

エレキベア
これで初期化は完了クマ〜〜〜
描画処理

マイケル
次は実際の描画処理・・・ということで、OnRender関数に処理を記述していきます。
最終的に下記のようになります!
最終的に下記のようになります!

エレキベア
これはパッと見で大体分かりそうクマね

マイケル
最初に図で載せた下記のようなイメージになるね!
一応これも一つ一つ見ていこう!
一応これも一つ一つ見ていこう!
コマンドリストのリセット

マイケル
まずはループの初めにコマンドリストをリセットします。
これは特に説明不要ですね!
これは特に説明不要ですね!
コマンドリストの生成

マイケル
そして次は実際にGPUへ送る命令を記述しています。
冒頭で「バリア」という用語を「コマンド実行時にリソースが何の用途に使用されるのかをGPUに伝えるもの」と紹介しましたが、それが「リソースバリアの設定」の部分になります。
今回だとPRESENT状態からRENDER_TAGET状態に移行する、と伝えてコマンドを格納した後にPRESENT状態に戻しています。
冒頭で「バリア」という用語を「コマンド実行時にリソースが何の用途に使用されるのかをGPUに伝えるもの」と紹介しましたが、それが「リソースバリアの設定」の部分になります。
今回だとPRESENT状態からRENDER_TAGET状態に移行する、と伝えてコマンドを格納した後にPRESENT状態に戻しています。

エレキベア
リソースの使用用途を伝えるのはそういうことだったクマね

マイケル
状態を切り替えたら、ディスクリプタヒープから情報を取り出してレンダーターゲットを設定し、画面の色も変更(今回は黄色単色)します。
一通りの命令を格納したらクローズするのも忘れないようにしましょう!
一通りの命令を格納したらクローズするのも忘れないようにしましょう!
コマンドリストの実行

マイケル
あとはコマンドリストを実行するのみ!
実行後はスワップチェーンオブジェクトから画面をスワップしています。
実行後はスワップチェーンオブジェクトから画面をスワップしています。

エレキベア
ここで溜めた処理が実行されるクマね
GPU処理の終了を待機

マイケル
最後に、生成したフェンスオブジェクトを使用してGPU処理の終了を待機します。

エレキベア
これで実装は完了クマ〜〜〜!!
実行!

マイケル
この状態で実行し、下記のように真っ黄色の画面が表示されれば成功です!!

エレキベア
やったクマ〜〜〜〜

マイケル
ループを確かめたい場合は、フレームごとに色を少しずつ変えたり等すれば変化することも確認できるはずです!
ポリゴンを表示する

マイケル
さあここまで来たらあと一息!
ポリゴンを表示してみましょう!!
ポリゴンを表示してみましょう!!

エレキベア
そういえばまだポリゴンすら表示できてなかったクマ・・・
頂点シェーダーとピクセル(フラグメント)シェーダー

マイケル
DirectXの場合は2Dオブジェクトを表示するだけでもシェーダーを書く必要があるため、
頂点シェーダーとピクセルシェーダーを実際に書いていきます。
シェーダについては冒頭でも軽く紹介しましたが、下記記事でも紹介しているため、よければそちらもご参考ください!
頂点シェーダーとピクセルシェーダーを実際に書いていきます。
シェーダについては冒頭でも軽く紹介しましたが、下記記事でも紹介しているため、よければそちらもご参考ください!
【C++】第四回 C++を使ったゲーム開発 〜3Dゲーム開発基礎 fbx読込とシェーダ編〜

エレキベア
懐かしい記事クマ〜〜〜
シェーダーファイルの作成

マイケル
それでは早速作成していきましょう!
まずは頂点シェーダーからですが、ファイルの追加から「頂点シェーダーファイル」を選択して雛形を作成することができます。
今回は「BasicVertexShader.hlsl」というファイル名で作成しました。
まずは頂点シェーダーからですが、ファイルの追加から「頂点シェーダーファイル」を選択して雛形を作成することができます。
今回は「BasicVertexShader.hlsl」というファイル名で作成しました。

マイケル
作成後、下記の内容に修正します。
頂点位置をそのまま返すだけのシンプルなものになります。
頂点位置をそのまま返すだけのシンプルなものになります。
↑頂点シェーダー処理の記述

マイケル
後はシェーダーファイルを右クリックし、プロパティからエントリポイント名、シェーダーモデルを設定すれば作成完了です!!

マイケル
同様にピクセルシェーダーも作成します。
↑処理の記述(青色単色で返す)

マイケル
これでシェーダーの準備は完了です!

エレキベア
あとはこれを読み込んで表示クマ〜〜〜!!
頂点座標とインデックス座標

マイケル
実装していく前に前提知識になりますが、頂点座標に加えてインデックス座標の概念も知っておく必要があります。
こちらは下記記事でも簡単に解説していますので、よければご参照ください!
こちらは下記記事でも簡単に解説していますので、よければご参照ください!
【C++】第三回 C++を使ったゲーム開発 〜3Dゲーム開発基礎 OpenGLと座標変換編〜

エレキベア
これも懐かしいクマね〜〜

マイケル
簡単にいうと、インデックス座標は頂点にインデックス値を与えることで複数回参照する処理を効率化する仕組みです。
例として下記のように4つの頂点があった場合、0〜3のインデックスを振ってあげることで「0,1,2」「0,2,3」といった座標で参照することができます。
例として下記のように4つの頂点があった場合、0〜3のインデックスを振ってあげることで「0,1,2」「0,2,3」といった座標で参照することができます。
↑頂点座標
↑インデックス座標

エレキベア
今回も四角形を描画するために三角ポリゴンを2つ描画するクマね
シェーダーファイルの読み込みとポリゴン描画

マイケル
それではシェーダーファイルを読み込んでポリゴンを描画させていきます。
最終的には下記のようになります!
最終的には下記のようになります!

マイケル
「// ★~~」で記述したコメントが追加箇所になるのですが、それなりに量もあるので一つ一つ見ていきましょう!

エレキベア
だいぶコードも多くなったクマね〜〜〜
必要なオブジェクトを定義

マイケル
新たに必要となるオブジェクト、関数は下記になります。
パイプラインステート、ルートシグネチャ、シェーダ関連のオブジェクトに加えて、ビューポート、シザー短形といった表示領域を設定するオブジェクトも必要になります。
パイプラインステート、ルートシグネチャ、シェーダ関連のオブジェクトに加えて、ビューポート、シザー短形といった表示領域を設定するオブジェクトも必要になります。

マイケル
今回はビューポート、シザー短形については単純にウィンドウの幅を設定するだけで問題ありません。
あとはLoadPipelineの後にLoadAssets関数を定義し、ここでシェーダの読み込みや設定を行うようにしていきます。
あとはLoadPipelineの後にLoadAssets関数を定義し、ここでシェーダの読み込みや設定を行うようにしていきます。

エレキベア
LoadAssetsに処理を書いていくクマね
ルートシグネチャの生成

マイケル
まずはルートシグネチャの生成です。
これは冒頭の概要で軽く触れた通り、ディスクリプタテーブル(ディスクリプタヒープとシェーダーのレジスタを関連付けたもの)をまとめるものになりますが、今回は座標を定義して渡すだけなので特に設定するものはありません。
しかし、パイプラインステートの生成で必要になるため初期化のみ行なっています。
これは冒頭の概要で軽く触れた通り、ディスクリプタテーブル(ディスクリプタヒープとシェーダーのレジスタを関連付けたもの)をまとめるものになりますが、今回は座標を定義して渡すだけなので特に設定するものはありません。
しかし、パイプラインステートの生成で必要になるため初期化のみ行なっています。

エレキベア
今回は役目無しクマか・・・
パイプラインステートの生成

マイケル
そして次はパイプラインステートの生成になります。
これが冒頭で紹介したPipelineStateObject(PSO)になりますね。
これが冒頭で紹介したPipelineStateObject(PSO)になりますね。

マイケル
ここでシェーダーファイルを実際に読みこんで設定しています。
この時頂点レイアウトを生成することで、シェーダーに渡すデータを定義することができます。
この時頂点レイアウトを生成することで、シェーダーに渡すデータを定義することができます。

エレキベア
いろいろ設定項目はあるクマが、
まあ今回は頂点シェーダ、ピクセルシェーダを設定しているだけクマね
まあ今回は頂点シェーダ、ピクセルシェーダを設定しているだけクマね
頂点バッファビュー、インデックスバッファビューの生成

マイケル
次に頂点座標、インデックス座標を直接定義して、バッファビューとして生成します。
バッファビューというのは、座標を定義したバッファ(メモリ領域)を渡すための設定情報というようなイメージです。
バッファビューというのは、座標を定義したバッファ(メモリ領域)を渡すための設定情報というようなイメージです。

エレキベア
最終的にはバッファビューの形式にしてGPUに渡せるようにするクマね
コマンド命令の追加

マイケル
最後に、これらを用いてコマンドリストに描画命令を追加します。
パイプラインステート、ルートシグネチャといった必要なオブジェクトを設定し、
バッファビューの設定とともに描画処理を追加します。
パイプラインステート、ルートシグネチャといった必要なオブジェクトを設定し、
バッファビューの設定とともに描画処理を追加します。

マイケル
DrawIndexedInstancedには、インデックス座標の数である6を設定しています。
これにて一通りの処理の実装は完了です!!
これにて一通りの処理の実装は完了です!!

エレキベア
ついにクマ・・・・
実行!

マイケル
実装が完了したところで実行・・・!
これで下記のように青色の四角形が描画されれば成功です!!
これで下記のように青色の四角形が描画されれば成功です!!

エレキベア
やったクマ〜〜〜!!
長かったクマ〜〜〜〜
長かったクマ〜〜〜〜
おわりに

マイケル
というわけで今回はDirectX12を用いたポリゴン描画でした!
どうだったかな??
どうだったかな??

エレキベア
噂に聞いていた通り大変だったクマ・・・
でも一つ一つ見ていけば、特段難しいことをやっている感じでもなかったクマね
でも一つ一つ見ていけば、特段難しいことをやっている感じでもなかったクマね

マイケル
実際に書いてみて、ハードルが高いと言われている理由は
・前提知識(シェーダーや座標周り)が必要
・公式チュートリアルの情報が最小限かつ基本は英語
・専門用語が多く、パイプラインも複雑
・生成が必要なオブジェクト、設定量が多い
・今はゲームエンジンで簡単に作れるのでモチベーションが出にくい
といったところになるのかなと思ったよ。
・前提知識(シェーダーや座標周り)が必要
・公式チュートリアルの情報が最小限かつ基本は英語
・専門用語が多く、パイプラインも複雑
・生成が必要なオブジェクト、設定量が多い
・今はゲームエンジンで簡単に作れるのでモチベーションが出にくい
といったところになるのかなと思ったよ。

エレキベア
初っ端から手を出すのはかなり厳しそうクマね

マイケル
この記事も量がかなり多くなってしまった・・・
今後もとりあえずFBXモデル表示くらいまでは作ってみようと思うからお楽しみに!
それでは今日はこの辺でアデューー!!
今後もとりあえずFBXモデル表示くらいまでは作ってみようと思うからお楽しみに!
それでは今日はこの辺でアデューー!!

エレキベア
クマ〜〜〜〜〜〜
【DirextX12】第一回 DirextX12を使ったゲーム開発 〜基礎知識からポリゴン描画まで〜 〜完〜
※次回の記事はこちら!