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

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

マイケル
今回は引き続きDirectXを触っていきます!
前回はコードで定義した3Dモデルを描画したので、今回は実際にFBXファイルを読み込んで描画するところまでやってみます!
前回はコードで定義した3Dモデルを描画したので、今回は実際にFBXファイルを読み込んで描画するところまでやってみます!
↑前回までの記事

エレキベア
ついにモデル描画まで出来るクマね
長かったクマ〜〜〜
長かったクマ〜〜〜

マイケル
毎度のごとく、作ったサンプルはGitHubにも上げています!
こちらも一緒にご参照ください!
こちらも一緒にご参照ください!
GitHub/masarito617 – cpp-dx12-sample-3d-fbx
↑今回作ったサンプル

エレキベア
サンプルも溜まってきたクマね

マイケル
また、前回作ったところから続きとして進めていきますが、
DirectX12の基本的な使い方が知りたい方は前回までの記事や公式サイト、下記書籍等を一読してみることをおすすめします!
DirectX12の基本的な使い方が知りたい方は前回までの記事や公式サイト、下記書籍等を一読してみることをおすすめします!
Direct3D 12 プログラミング ガイド – Win32 apps | Microsoft Learn
DirectX 12の魔導書 3Dレンダリングの基礎からMMDモデルを踊らせるまで

エレキベア
日本語書籍はありがたいクマ〜〜〜
FBX SDKの導入

マイケル
それでは早速進めていきますが、今回はFBXファイルを読み込むにあたり、FBX SDKというAutoDesk公式のライブラリを使用します!

エレキベア
FBX SDKは前も一度使用したことがあったクマね
↑以前FBXSDKを使用した際の記事

マイケル
いや〜〜懐かしいね
基本的に同じように使っていくから、復習のつもりでやってみよう!
基本的に同じように使っていくから、復習のつもりでやってみよう!

マイケル
ライブラリのダウンロード、インストールは公式サイトから行います。
インストールしたら下記のように環境変数を定義しておきましょう!
今回は「FBXSDK_DIR」という名称で定義しました。
インストールしたら下記のように環境変数を定義しておきましょう!
今回は「FBXSDK_DIR」という名称で定義しました。

マイケル
そして追加のインストールディレクトリ、追加のライブラリディレクトリにもそれぞれパスを追加します。
DirectXTexを定義済だと思うので、その後ろに追加しましょう。
DirectXTexを定義済だと思うので、その後ろに追加しましょう。

エレキベア
この辺りはもう定番クマね

マイケル
あとはC++のクラスに下記のようにインクルードを追加、ビルドして
エラーが出ないことが確認できれば導入は完了です!
エラーが出ないことが確認できれば導入は完了です!
↑インクルードを追加してみる
FBXモデルのロード処理
FbxLoaderクラスを追加

マイケル
FBX SDKの導入が完了したら、実際にFBXファイルのロード処理を記述していきます。
今回は FbxLoader.h、FbxLoader.cppとして新たに作成しました。
今回は FbxLoader.h、FbxLoader.cppとして新たに作成しました。
↑FbxLoader.h
↑FbxLoader.cpp

マイケル
処理の内容は単純で、マネージャー、インポーターといったロードに必要なオブジェクトを作成した後にファイルパスから頂点情報を読み込んでいます。
今回は頂点座標、インデックス座標、UV座標に加えて法線座標も一緒に読み込むようにしました。
今回は頂点座標、インデックス座標、UV座標に加えて法線座標も一緒に読み込むようにしました。

エレキベア
UVセットが一つしか読めなかったり、簡易的な実装になっているのには注意クマね

マイケル
それから、UV座標のV値を1から引くことで反転させていることにも注意が必要です。
これは自分がBlenderでモデルを作成したこと影響もあり、(0,0)の原点が左下になっていたためです。
これは自分がBlenderでモデルを作成したこと影響もあり、(0,0)の原点が左下になっていたためです。

エレキベア
使用するソフトによってはちょっとした違いもあるのクマね

マイケル
また下記処理の部分については、UV座標、法線座標が異なる頂点についてもインデックス座標が同一のものが存在していたために、インデックス座標を振り直す処理を行なっています。
こちらは前回の記事で死闘を繰り広げた内容を書いていますので、詳細はそちらをご参照ください!
こちらは前回の記事で死闘を繰り広げた内容を書いていますので、詳細はそちらをご参照ください!
【C++】第四回 C++を使ったゲーム開発 〜3Dゲーム開発基礎 fbx読込とシェーダ編〜
法線座標、UV座標の読み込み
↑法線、UV座標が同一の頂点についてインデックス座標を振り直している

エレキベア
これはマジでどうにかしたいクマ・・
FBXファイルのロード処理

マイケル
ロード処理の実装が完了したため、頂点座標を直接定義していた箇所を置き換えてみましょう。
今回はBlenderで作成したサイコロを読み込んでみます。
今回はBlenderで作成したサイコロを読み込んでみます。
↑頂点情報をfbxファイルから読み込む

エレキベア
綺麗に置き換えられたクマね

マイケル
あとは法線座標も読み込むようにしたため、頂点レイアウトも下記のように修正しておきましょう。
↑入力レイアウトに法線情報を追加

マイケル
これを機に3つのファイルに分かれていたシェーダーファイルも一つのファイルに統一しました。
こちらの方が見やすいですね!
こちらの方が見やすいですね!
↑シェーダーを一つにまとめた

マイケル
この状態で実行すれば、下記のようにモデルが描画されるはずです!

エレキベア
サイコロクマ〜〜〜〜〜

マイケル
ついでに他のモデルでも試してみます!
下記はゴロヤンのモデルです。
下記はゴロヤンのモデルです。

エレキベア
なぜこれを選んだクマ・・・

ゴロヤン
ゴロ〜〜〜〜〜〜
Lumbert拡散反射での描画

マイケル
せっかく法線座標も読み込めるようにしたので、Lumbert拡散反射の処理も追加して簡易的な影も付けてみます。

エレキベア
ランバート反射は確か、法線と光源の向きから拡散反射量を求める内容だったクマね

マイケル
全ての面に同じ角度で一つの光源が当たっていると考える、擬似的な反射シミュレートだね
詳しくは下記記事で紹介しているので、そちらをご参照ください!
詳しくは下記記事で紹介しているので、そちらをご参照ください!
【C++】第四回 C++を使ったゲーム開発 〜3Dゲーム開発基礎 fbx読込とシェーダ編〜
ランバート反射モデル

エレキベア
懐かしいクマ〜〜〜

マイケル
ランバート反射のシェーダーは下記のようになります。
内容としてはシンプルなものですね。
内容としてはシンプルなものですね。
↑Lambert拡散反射シェーダー

マイケル
この反射量を求めるために
・環境光
・光のカラー
・光の向き
の情報が必要になるため、こちらも追加でシェーダーに渡すようにしていきます!
また、法線座標もワールド座標で変換する必要があるため、ワールド座標行列とビュー射影行列はそれぞれ独立して渡すようにします。
・環境光
・光のカラー
・光の向き
の情報が必要になるため、こちらも追加でシェーダーに渡すようにしていきます!
また、法線座標もワールド座標で変換する必要があるため、ワールド座標行列とビュー射影行列はそれぞれ独立して渡すようにします。

エレキベア
定数バッファを追加で渡す必要がありそうクマね

マイケル
ひとまずは下記のようにMatricesData、LightingDataとして定義してこれらを渡すようにしていこうと思います。
↑座標変換マトリクスの分離とライティング用データの追加

マイケル
定数バッファ(CBV)を一つ増やす必要があるため、下記のようにディスクリプタヒープとディスクリプタテーブルの数の指定を修正しておきましょう。
↑ディスクリプタヒープ、ディスクリプタテーブルの指定を1つ増やす

マイケル
そしてCBV生成処理も下記のように修正すれば完了です!
↑CBVの生成処理

エレキベア
バッファービューを作るのも慣れてきたクマね

マイケル
この状態で実行すると下記のようになるはずです!
正常にランバート反射できていることが確認できます。
正常にランバート反射できていることが確認できます。

エレキベア
これぞ3Dクマ〜〜〜〜〜
深度バッファの指定

マイケル
さあこれで完了!!
・・・といいたいところですが、一点問題が残っています。
・・・といいたいところですが、一点問題が残っています。

マイケル
よく見ると、このように後ろにあるはずのメッシュが前面に描画されていることが分かります・・・

エレキベア
気づかなかったクマ・・・

マイケル
これは深度バッファーが指定されていないために発生する事象になります。
これはフラグを変えれば済む・・・という話でもなく深度バッファービュー(DSV)を生成して設定しなければならないようなのでこちらも生成しましょう!
これはフラグを変えれば済む・・・という話でもなく深度バッファービュー(DSV)を生成して設定しなければならないようなのでこちらも生成しましょう!

エレキベア
さすがDirectXクマ・・・

マイケル
とはいえ生成の方法はこれまでとさほど変わりはありません。
下記のようにディスクリプタヒープと深度バッファーの変数を定義して・・・
下記のようにディスクリプタヒープと深度バッファーの変数を定義して・・・
↑深度バッファーの定義を追加

マイケル
それぞれ初期化します!
↑深度バッファービューの生成

マイケル
あとはパイプラインステートとコマンドリストにも深度バッファを使用するよう設定すれば完了です!
↑パイプラインステートへの追加
↑深度ビューのクリア処理の追加

エレキベア
だいぶ雑クマがまあ大体分かるクマ〜〜〜

マイケル
この状態で実行すると、下記のように綺麗に描画されることが確認できました!

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

マイケル
というわけで今回はFBXモデルの描画でした!
どうだったかな??
どうだったかな??

エレキベア
FBX SDKは使ったことあったから楽勝だったクマね

マイケル
やっぱりモデルを描画できると感動するね〜〜

マイケル
当初はとりあえずFBXモデルの描画まで出来ればいいかなと思っていたけど、
せっかくここまで作ったので、ゲームエンジンとして使えるようリファクタリングして簡単なゲームも開発してみようかなと思います!
次回もお楽しみに〜〜〜!!
せっかくここまで作ったので、ゲームエンジンとして使えるようリファクタリングして簡単なゲームも開発してみようかなと思います!
次回もお楽しみに〜〜〜!!

エレキベア
クマ〜〜〜〜〜
【DirextX12】第四回 DirextX12を使ったゲーム開発 〜FBX SDKを使用した3Dモデル描画〜 〜完〜