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

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

マイケル
今回は前回に引き続きDirectX12を触っていきます!
前回はテクスチャ描画まで行ったので、今回は 座標変換と3Dオブジェクトを描画するところまで 進めていこうと思います。
前回はテクスチャ描画まで行ったので、今回は 座標変換と3Dオブジェクトを描画するところまで 進めていこうと思います。
↑前回までの記事

エレキベア
ついに3Dオブジェクトも表示できるようになるクマね

マイケル
今回は3Dモデルの読み込みは行わないけど、コードで書いた3Dのキューブを表示して簡単に動かせるところまで進めるから楽しくなってくると思うよ!

エレキベア
これまではマジで地味だったクマからね・・・

エレキベア
毎度お馴染みクマね

マイケル
それじゃ早速進めていこう!!
なお今回作ったサンプルについてはGitHubに上げていますので、こちらもよければご参考ください!
なお今回作ったサンプルについてはGitHubに上げていますので、こちらもよければご参考ください!
GitHub/masarito617 – cpp-dx12-sample-3d
↑今回作ったサンプル

エレキベア
これもまたお馴染みクマね

マイケル
また、実装方法については引き続き、下記の公式のサンプルと下記の書籍を参考にさせていただきました!
もっと詳しく知りたい方や理解を深めたい方は一読をおすすめします!
もっと詳しく知りたい方や理解を深めたい方は一読をおすすめします!
GitHub – microsoft / DirectX-Graphics-Samples
↑公式のサンプル
DirectX 12の魔導書 3Dレンダリングの基礎からMMDモデルを踊らせるまで

エレキベア
日本語の書籍はありがたいクマ〜〜〜
2Dポリゴンの位置をピクセル指定できるようにする
頂点座標の修正

マイケル
まずは現在表示している2Dポリゴンの位置をピクセルで指定できるように修正してみます。
現状は下記のようにスクリーン座標を直で入力して指定しています。
現状は下記のようにスクリーン座標を直で入力して指定しています。
↑スクリーン座標を直接指定している

マイケル
これを下記のようにピクセル位置で指定するようにして、正常に描画されるよう修正を進めていきます。
↑ピクセル位置で指定できるようする

エレキベア
確かに2Dオブジェクトはピクセル位置で指定できるようにした方が便利クマね

マイケル
これができるようになれば、2DゲームやUIも作れるようになるはず!
張り切っていきましょう!!
張り切っていきましょう!!
頂点シェーダーの修正

マイケル
このピクセル位置から最終的なスクリーン座標に変換するには、行列を用いた座標変換を行う方法が用いられます。
これについて詳しくは下記記事にまとめてありますので、こちらもご参考ください!
これについて詳しくは下記記事にまとめてありますので、こちらもご参考ください!

エレキベア
前はOpenGLとGLSLを使って座標変換したクマね

マイケル
今回も下記のようにシェーダーに変換するための行列を渡して、オブジェクトの頂点座標と掛け合わせることで座標を変換します。
↑行列を渡して座標変換を行う

エレキベア
シェーダーに変換するための行列を渡せばOKクマね
ディスクリプタテーブルの修正

マイケル
行列を渡すには、定数バッファービュー(CBV)という形式で渡すことになります。
シェーダーリソースビューと同様、ディスクリプタテーブルに設定して渡す形式になるため、下記のようにインデックスを増やして設定します。
シェーダーリソースビューと同様、ディスクリプタテーブルに設定して渡す形式になるため、下記のようにインデックスを増やして設定します。
↑ディスクリプタテーブルの生成処理を修正

マイケル
今回はCBV->SRVの順で設定し、ルートパラメータは同一のものを指定しています。
頂点シェーダーからも見えるように、D3D12_SHADER_VISIBILITY_ALLで指定するようにしましょう!
頂点シェーダーからも見えるように、D3D12_SHADER_VISIBILITY_ALLで指定するようにしましょう!

エレキベア
こんな感じで配列のサイズを変えて設定するクマね
定数バッファービューの生成

マイケル
そしてここからは実際に定数バッファーに変換行列を設定して渡すようにしていきます。
まずはディスクリプタヒープについてですが、これはシェーダーリソースビューで使用していたものを共用で使用して問題ありません。
そのため下記のように名前を変更して、サイズも2つ分取るよう修正しておきます。
まずはディスクリプタヒープについてですが、これはシェーダーリソースビューで使用していたものを共用で使用して問題ありません。
そのため下記のように名前を変更して、サイズも2つ分取るよう修正しておきます。
↑ディスクリプタヒープはシェーダーリソースビューと共用するため名前とサイズを変える

エレキベア
ディスクリプタヒープはディスクリプタをまとめる役割だったクマね

マイケル
そして次にDirectXに搭載されているDirectX::XMMATRIXを使用して行列を生成していくのですが、列優先、行優先でC++側とHLSL側で行列の扱いが異なってくるため注意が必要です。
参考(とても分かりやすい):
列優先(Column-major),行優先(Row-major)は複数ある – Qiita

マイケル
行優先は左から右に乗算していき、列優先は右から左へ乗算します。
DirectX::XMMATRIXは行優先、HLSLは列優先です。
DirectX::XMMATRIXは行優先、HLSLは列優先です。

エレキベア
OpenGLも確か列優先だったクマね

マイケル
数学でも列優先表現を用いることが多いみたいだね。
とにもかくにも、乗算する順番が変わってくることには注意しよう!
実際に変換用の行列を作成している箇所は下記になります。
とにもかくにも、乗算する順番が変わってくることには注意しよう!
実際に変換用の行列を作成している箇所は下記になります。
↑定数バッファーの生成

マイケル
下記の2D用のビュー射影行列を作成して設定しています。
また、今回はディスクリプタヒープを共用で使用するため、事前にハンドルを取得しておき、設定したらポインタをオフセットする必要があることにも注意しましょう!
また、今回はディスクリプタヒープを共用で使用するため、事前にハンドルを取得しておき、設定したらポインタをオフセットする必要があることにも注意しましょう!
↑2D用ビュー射影行列

マイケル
シェーダーリソースビューもオフセットした後のハンドルを指定して生成するよう修正しておきます。
↑シェーダーリソースビューの生成時に渡すハンドルはオフセットしたものにする

エレキベア
これで行列が渡せたクマね
実行!

マイケル
それでは正常に変換されているか確認してみましょう!
実行して下記のように表示されれば成功です!
実行して下記のように表示されれば成功です!

エレキベア
綺麗に表示できたクマね

マイケル
このままだと小さすぎるのもあるので、大きさや座標位置も変えて確認してみましょう!
↑位置と大きさを修正

マイケル
いい感じですね!!

エレキベア
これで2Dは完璧クマ〜〜〜
2Dポリゴンを3D空間上で動かす
3D座標の変換を行う

マイケル
次はいよいよこの2Dプレーンを3Dオブジェクトとして描画してみます!
とはいえ、基本的に変換する行列を変えてあげるだけなので簡単です。
とはいえ、基本的に変換する行列を変えてあげるだけなので簡単です。

エレキベア
いよいよ3D空間に突入クマね

マイケル
まずは頂点座標をピクセル位置ではなく、オブジェクトのローカル座標を想定して設定します。
↑3Dオブジェクトのローカル座標の形式で設定

マイケル
ここから変換用の行列を設定していきますが、3Dの場合は「ワールド座標」「ビュー座標」「射影座標」の3つの行列を使用して作成します。
こちらについても詳細は過去に書いた記事をご参照ください!
こちらについても詳細は過去に書いた記事をご参照ください!

マイケル
行優先の場合は、下記のように
ワールド座標 * ビュー座標 * 射影座標
でローカル座標を変換するための行列を作成することができます。
ワールド座標 * ビュー座標 * 射影座標
でローカル座標を変換するための行列を作成することができます。
↑3Dの座標変換式

エレキベア
C++側ではそのまま掛ければいいわけクマね

マイケル
ヘッダーファイルにも必要な行列を定義して、下記のように変換行列を作成して設定します。
出力結果が分かりやすいよう、少しだけ回転も入れています。
出力結果が分かりやすいよう、少しだけ回転も入れています。
↑変換に必要な行列を定義
↑3D用の変換行列を設定する

マイケル
以上で実装は完了です!!

エレキベア
行列の計算部分が理解できていれさえいれば簡単クマね
実行!

マイケル
これを実行してみると、下記のように少し傾いたオブジェクトが描画されるはずです!

エレキベア
小せえ・・・

マイケル
これだと少し見にくいので、Scale値も追加で設定してみましょう!

エレキベア
大きさを変えるのも簡単になったクマね
回転させてみる

マイケル
あとはせっかくなので、動作確認がてら動かして遊んでみましょう!
下記のようにUpdate内で回転角度を変更してみます。
下記のようにUpdate内で回転角度を変更してみます。
↑ようやくUpdateの使い道が出てきた

マイケル
また、デフォルトだとカリングが効いて裏面が描画されないため、
ラスタライズステートにD3D12_CULL_MODE_NONEを指定して裏面も表示するよう変更しておきます。
ラスタライズステートにD3D12_CULL_MODE_NONEを指定して裏面も表示するよう変更しておきます。
↑裏面も表示させる

エレキベア
段々ゲームエンジンを使ってる感覚に近づいてきたクマね
実行!

マイケル
ここまで実装したところで実行!
下記のように回転すれば成功です!!
下記のように回転すれば成功です!!

エレキベア
こんな適当な絵なのに感動クマ・・・
3Dのキューブを描画して動かす
3Dキューブの座標を定義する

マイケル
以上で座標変換の実装は完了なのですが、3D感がまだ薄いと思うので、
最後に3Dのキューブを描画して終わろうと思います!
最後に3Dのキューブを描画して終わろうと思います!

エレキベア
待ってましたクマ〜〜〜

マイケル
とはいえ頂点座標、インデックス座標と描画時のサイズ指定を変更するだけですね!
今回はインデックス座標は全振りで下記のように指定してみます。
今回はインデックス座標は全振りで下記のように指定してみます。
↑コードでキューブになるよう定義してみる

エレキベア
実際の3Dモデルもこんな感じで定義されているクマね
実行!

マイケル
これで実行して下記のように描画されれば成功です!!

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

マイケル
回転方向を変えてみたりしても問題ないことが確認できます!!

エレキベア
適当な画像なのに感動クマ・・・
おわりに

マイケル
というわけで今回は座標変換と3Dオブジェクトの描画でした!
どうだったかな??
どうだったかな??

エレキベア
3D描画できるとやっぱ嬉しいクマね〜〜
DirectXでゲーム開発するイメージも湧いてきたクマ
DirectXでゲーム開発するイメージも湧いてきたクマ

マイケル
今回はコードで3Dキューブの座標を定義したけど、あとは3Dモデルのファイルから頂点座標やUV座標を読み込んで設定さえ出来れば自由にモデルも動かせそうだね!
その辺りは次回やってみようと思うからお楽しみに!!
その辺りは次回やってみようと思うからお楽しみに!!

エレキベア
楽しみクマ〜〜〜〜〜

マイケル
それでは今日はこの辺で!!
アデューー!!
アデューー!!

エレキベア
クマ〜〜〜〜〜〜
【DirextX12】第三回 DirextX12を使ったゲーム開発 〜座標変換と3Dオブジェクト表示〜 〜完〜
※次回の記事はこちら!