とにかくC++でDirectX12を動かしてみる

はじめましてJWordのS.Tです。普段はWindowsアプリ関連の開発を行っていますが、今回は業務内容とは全く関係ないDirectX12で遊んでみようと思います。
私はDirectX11以前の使用経験はありますが(ここにたどり着いたほとんどの方はそうだと思いますが)、12は勉強しながらブログを書いてますのでお手柔らかにお願いします(笑)
とにかくソースを貼り付けて動かすのが目的なので解説の内容は薄めです。

■環境

OS: Windows 10
IDE: Visual Studio 2015 Community
SDK: Windows 10 SDK

■初期設定

ファイルメニュー → 新規作成 → プロジェクトを選択すると下記のようなダイアログが表示されるので
テンプレート → Visual C++ → Windows → Win32を選択してWin32 プロジェクトを選択します。
名前はプロジェクト名になるので「DirectX12Test」とでもしておきましょう。1

ウィザードが表示されるので空のプロジェクトにチェックを入れます。
DirectX12の雛形を作成してくれるプロジェクトもあるようですが、今回は勉強のためにあえて空のプロジェクトを選択します。2

参照設定ですが、Windows 10 SDKにDirectXも含まれるのでそのインストール先を設定します。
プロジェクトメニュー → DirectX12Test のプロパティを選択すると下記ののようなダイアログが表示されるので
構成プロパティ → VC++ ディレクトリ → インクルード ディレクトリ → 右のプルダウンボタン → リストの<編集…>を選択します。5
「C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um」のように最新のバージョンを指定します(2016/09/23現在の最新バージョンは10.0.14393)
同様にインクルード ディレクトリに「C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\shared」、
ライブラリ ディレクトリに「C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0\um\x86」を追加します。6

■コーディング

プロジェクトが作成されるのでいよいよここからコーディングです。
左のソリューションエクスプローラーのソースファイルを右クリックし、表示されたメニューの追加 → 新しい項目を選択します。3

main.cppを追加します。

4

宣言部分です。C++であれば普通はクラス化すると思いますが、全体的な流れがわかりやすくなるようにmain.cppにまとめています。

メイン関数とウィンドウプロシージャを記述します。ウィンドウを作成しそのウィンドウハンドルを使ってDirectXを初期化、
その後ウィンドウを表示してお約束のメッセージループです。

DirectXの初期化です。デバッグ時はデバッグレイヤーを有効にし、有効なハードウェアアダプタを調べます。
D3D12CreateDeviceが失敗する場合はビデオカードがDirectX12に対応していないのでg_useWarpDeviceをtrueにしてみてください。
WARPデバイス(ソフトウェア)を使用するようになりますのでまず動くと思います。

初期化が長いので分割します。
コマンドキューを作成します。DirectX12ではコマンドリストというものがあってコマンドキューに渡して描画を実行するようです。
要はウィンドウメッセージのように溜め込んでおいて順番に実行するような感じです。
そして作成したウィンドウのハンドルを元にスワップチェインを作成します(DirectX11以前にもあったので解説は省略)

記述子ヒープを作成します。何やら難しげな用語が出てきましたがレンダーターゲットビューを作成するために必要なものらしいです。
レンダーターゲットビューをフレームバッファとバックバッファ用に2つ作成し、
コマンドアロケーターを作成します。これを作成しておかないとコマンドリストを実行できません。
また、ルートシグネチャというものがあり、定数バッファとシェーダーの関連付けを行うために必要ですが、今回は定数バッファは使用しないので空のルートシグネチャを作成します。

シェーダーのコンパイルですが後述のhlslファイルを読み込んでコンパイルします。(ここらへんも以前と一緒なので省略)
描画関連の設定をしてコマンドリストを作成します。

ようやく頂点バッファの作成です。Map/Unmapで頂点データをコピーするのは変わっていませんが、
GPUにアップロードされるまで待機する必要があるようです。
長々と書いてきましたがここまでがInit関数です。

描画ですが、コマンドアロケーターをリセット → コマンドリストをリセット → ルートシグネチャを設定後に描画処理を行う必要があるようです。
描画後にWaitForPreviousFrameでコマンドキューと同期する必要があります。

同期用の関数です。
MSによると下記は必要最低限の簡易実装であり、効率的にGPUを使用する方法は他のサンプルを見てくださいとのこと。

以上のプログラムをmain.cppに貼り付けてビルドしてください。
最後にmain.cppと同じフォルダに「sharders.hlsl」というファイル名で以下を保存してください。
頂点シェーダーとピクセルシェーダーですが特に何もしてません。ただ頂点カラーを出力しているだけです。

実行するとウィンドウが表示され中央に三角形が表示されているはずです。
長々と書いてきましたがこれで終了です。お疲れさまでした。
今回はほとんど初期化で終わってしまいましたが、次回?があればもう少し凝ったことをしてみたいと思います。

参考
https://msdn.microsoft.com/en-us/library/windows/desktop/dn859356(v=vs.85).aspx

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です