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

エレキベア
クマ〜〜〜〜

マイケル
今日も前回に引き続き、C++でのゲーム開発を進めていくよ!
前回は3Dゲーム開発基礎編ということで、座標変換周りを解説していきましたが、
今回も基礎編で fbx読込とシェーダ編 になります!
前回は3Dゲーム開発基礎編ということで、座標変換周りを解説していきましたが、
今回も基礎編で fbx読込とシェーダ編 になります!
↑前回の記事
↑本記事での解説範囲

エレキベア
シェーダは聞いたことあるクマ〜〜〜

マイケル
サンプルプロジェクトは前回と同じもので、
4種類のシェーダで3Dモデルを描画するサンプルになっています。
4種類のシェーダで3Dモデルを描画するサンプルになっています。
↑4種類のシェーダを実装している

マイケル
それでは早速進めていきましょう!
参考書籍

マイケル
前回と同様、基本的な実装については下記書籍をベースに作成しています。

マイケル
そして数式や理論に関してはところどころ
下記2冊と照らし合わせながら整理しました。
下記2冊と照らし合わせながら整理しました。

エレキベア
どの本も広く網羅されているから
おすすめクマ〜〜〜〜
おすすめクマ〜〜〜〜
使用したモデル

マイケル
書籍ではgpmeshファイルを読み込む方向で記載されていましたが、
やはり fbxファイル の方が馴染みがあるので、こちらを読み込むよう実装していこうと思います!
やはり fbxファイル の方が馴染みがあるので、こちらを読み込むよう実装していこうと思います!

マイケル
というわけで3D読込で使用したサンプルモデルは以下になります。
Blenderで作成した立方体にサイコロテクスチャを貼っただけの
シンプルなfbxモデル です。
Blenderで作成した立方体にサイコロテクスチャを貼っただけの
シンプルなfbxモデル です。
↑Blenderで作成
↑サイコロのテクスチャ

マイケル
こちらもプロジェクト内に含めているので、
ご自由にお使いください!
ご自由にお使いください!

エレキベア
これはクマでも作れるクマ〜〜〜
fbxsdkでのロード処理

マイケル
今回fbxモデルを読み込むにあたって、
AutoDesk社が提供している fbxsdk というライブラリを使用させていただきました!
AutoDesk社が提供している fbxsdk というライブラリを使用させていただきました!

マイケル
インストール方法については省略しますが、
基本的にインストールしてパスを通すだけで使えるかと思います!
基本的にインストールしてパスを通すだけで使えるかと思います!

エレキベア
準備完了クマ〜〜〜〜
最終的な座標の形式

マイケル
まず最終的に座標をどのように設定したいかについてですが、
下記のようにVertexArrayクラスに 頂点バッファとインデックスバッファ を渡して
シェーダに設定する形となります。
下記のようにVertexArrayクラスに 頂点バッファとインデックスバッファ を渡して
シェーダに設定する形となります。

マイケル
そして今回はライティングに必要なパラメータとして、
位置座標、法線座標、UV座標 も必要となります。
そのため頂点バッファは下記のように、8つで1セットとして渡す形にします。
位置座標、法線座標、UV座標 も必要となります。
そのため頂点バッファは下記のように、8つで1セットとして渡す形にします。
↑最終的に位置座標、法線座標、UV座標を1セットとして渡す

エレキベア
読み込んだ座標情報をこの形に直して設定するクマね
初期化処理

マイケル
渡す形を認識した上で、fbxsdkを使って読み込んでいきます!
まずは下記のように初期化処理を行い、ファイルを読み込みましょう!
まずは下記のように初期化処理を行い、ファイルを読み込みましょう!
頂点座標の読込

マイケル
ファイルを読み込んでメッシュ取得までできたら、
GetControlPointsCount() で頂点座標を取得することができます。
GetControlPointsCount() で頂点座標を取得することができます。

エレキベア
これだけで取得できるのは便利クマ〜〜〜〜〜
インデックス座標の読込

マイケル
そしてインデックス座標に関しては、GetPolygonVertex() で取得できます。
このインデックスは頂点座標と対応しているため、ここから頂点座標を取得することもできます!
このインデックスは頂点座標と対応しているため、ここから頂点座標を取得することもできます!

マイケル
ここまで読み込んだ情報は下記のようになります。
↑頂点座標とインデックス座標の対応

エレキベア
ここまでは余裕クマね
法線座標、UV座標の読込

マイケル
法線座標、UV座標に関しても、インデックス座標と同様、
下記のように取得することができます。
下記のように取得することができます。

エレキベア
これで完了クマね〜〜〜〜
案外ちょろかったクマ
案外ちょろかったクマ

マイケル
そう、これで全ての座標が取得できたからそのまま渡せば完了!
・・・と思いきや・・・
・・・と思いきや・・・
↑崩壊したサイコロ達

マイケル
そのまま設定してしまうとこのようにモデルが崩壊してしまいます・・・

エレキベア
なんてことだクマ・・・・

マイケル
というのも法線、UV座標に関しては下記のように、
同じインデックス座標でも異なる座標のものがある からなんですね・・・。
同じインデックス座標でも異なる座標のものがある からなんですね・・・。
↑インデックス座標と法線・UV座標の対応
↑同じ頂点で異なるものがあるため、法線・UV座標が上書きされてしまう

エレキベア
これは困ったクマ〜〜〜・・・・

マイケル
そのため、今回設定する形に直すには、
法線、UV座標が異なるものについてインデックス座標を振り直す必要がある
ということになります。
法線、UV座標が異なるものについてインデックス座標を振り直す必要がある
ということになります。

マイケル
これを力技で実装したのが下記になります。
他にいい方法はあると思いますが、今回はこれで進めようと思います・・・。
他にいい方法はあると思いますが、今回はこれで進めようと思います・・・。

マイケル
これにより、振り直されたインデックス座標は下記のようになります。
↑インデックス座標を振り直した結果
↑振り直されたインデックス座標

マイケル
これを並び替えると、下記のように
1つの頂点について3つの頂点バッファがある状態になります。
1つの頂点について3つの頂点バッファがある状態になります。

エレキベア
これは立方体だからクマね

マイケル
これで必要な座標情報は一通り揃いました!
シェーダの描画

マイケル
それではシェーダの描画を行なっていきましょう!
シェーダは前回も少し触れましたが、受け取った座標を元に計算を行い描画を行うもの
になります。
シェーダは前回も少し触れましたが、受け取った座標を元に計算を行い描画を行うもの
になります。

マイケル
そしてシェーダは大きく
・頂点シェーダ
・フラグメントシェーダ
の2つに分かれており、それぞれ座標の計算と見た目の調整を行います!
・頂点シェーダ
・フラグメントシェーダ
の2つに分かれており、それぞれ座標の計算と見た目の調整を行います!
↑シェーダの描画プロセス

エレキベア
いよいよ後は描画するだけクマね

マイケル
今回はサンプルプロジェクトでも実装した、
基本となる下記4種類のシェーダを紹介します!
基本となる下記4種類のシェーダを紹介します!
[シェーダ種類]
・単色描画
・スプライト描画
・ランバート反射モデル
・フォン反射モデル

エレキベア
楽しみクマ〜〜〜
単色描画

マイケル
まずは単色での描画について!
今回は下記のように青色一色で描画しています!
今回は下記のように青色一色で描画しています!

エレキベア
これは簡単そうクマね

マイケル
受け取った座標情報を元に 頂点シェーダ内でクリップ座標まで変換 して、
フラグメントシェーダ内で出力色を指定 しているだけになるね!
フラグメントシェーダ内で出力色を指定 しているだけになるね!

マイケル
このシェーダでは法線座標、UV座標は使用せずに描画することができます!
1つ注意点をあげるとすれば、座標計算の前には vec4(inPosition, 1.0) というように
w成分を足して4要素にする必要があるくらいです。
1つ注意点をあげるとすれば、座標計算の前には vec4(inPosition, 1.0) というように
w成分を足して4要素にする必要があるくらいです。

エレキベア
はやく次にいくクマ〜〜〜
スプライト描画

マイケル
次はテクスチャを貼って描画したものになります。
ここからUV座標を使用しますが、法線座標についてはまだ使用しません。
ここからUV座標を使用しますが、法線座標についてはまだ使用しません。

エレキベア
3Dモデルっぽくなってきたクマね

マイケル
頂点シェーダでの計算は同じですが、受け取ったUV座標について
フラグメントシェーダに渡すようにしています。
フラグメントシェーダでは 受け取ったUV座標とテクスチャ情報から描画処理 を行います。
フラグメントシェーダに渡すようにしています。
フラグメントシェーダでは 受け取ったUV座標とテクスチャ情報から描画処理 を行います。

マイケル
テクスチャ情報については、下記のように読込処理を行い、
描画前にActiveにすることで自動的に設定 されます。
テクスチャの読込については第二回で使用した SDL_Imageライブラリ を使用しました。
描画前にActiveにすることで自動的に設定 されます。
テクスチャの読込については第二回で使用した SDL_Imageライブラリ を使用しました。

エレキベア
ここまでもまあ簡単クマね
ランバート反射モデル

マイケル
そして次はランバート反射モデル!
下記のように光の反射を考慮したモデルになります。
下記のように光の反射を考慮したモデルになります。

エレキベア
なんか難しそうなのが来たクマ・・・

マイケル
まず物がどのようにして見えているのかだけど、
これは 光源から出た光がいろんなところに反射して最終的に目に入ることで
見えていることになります。
影の中のものがうっすら見えるのも、周りの光がある程度反射しているためなのです。
これは 光源から出た光がいろんなところに反射して最終的に目に入ることで
見えていることになります。
影の中のものがうっすら見えるのも、周りの光がある程度反射しているためなのです。
↑光は反射しまくっている

マイケル
しかしこの反射を全て考慮してしまうと、計算負荷がとんでもないことになってしまう・・・。
そのためN次的な反射は考慮せずに、光源からの光が当たる量のみを考慮したモデルを
ランバート反射モデルといいます。
当たった光が全方位に拡散するという特性から 拡散反射モデル とも呼ばれます。
そのためN次的な反射は考慮せずに、光源からの光が当たる量のみを考慮したモデルを
ランバート反射モデルといいます。
当たった光が全方位に拡散するという特性から 拡散反射モデル とも呼ばれます。

エレキベア
それなら計算量はがくっと減りそうクマね

マイケル
計算方法としては、
頂点からの法線をN、頂点から光源へ向かうベクトルをL とした場合、
下記の計算で表すことができます。
頂点からの法線をN、頂点から光源へ向かうベクトルをL とした場合、
下記の計算で表すことができます。

マイケル
全てのオブジェクトに均一に当たる光(環境色)を最低値として設定し、
そこに 光の拡散反射量を加えたもの を反射量とする考え方です!
そこに 光の拡散反射量を加えたもの を反射量とする考え方です!

マイケル
具体的な実装は下記になります。
ここから法線座標も使用して計算することになります。
ここから法線座標も使用して計算することになります。

エレキベア
この話を聞いてから見ると分かってきたクマ

マイケル
環境色や光源についての情報は基本的にRendererクラスで定義して設定
するようにしています。
するようにしています。

エレキベア
光の原理が少しわかった気がして感動クマ〜〜

マイケル
ちなみに今回は頂点ごとに法線座標を持たせていますが、
面ごとに均一な法線座標を持たせる方法 もあります。
その場合はポリゴンの境界がくっきり見える結果となるので、カクツキが欲しい場合にはそちらの方法も試してみましょう!
面ごとに均一な法線座標を持たせる方法 もあります。
その場合はポリゴンの境界がくっきり見える結果となるので、カクツキが欲しい場合にはそちらの方法も試してみましょう!
フォン反射モデル

マイケル
そして最後はフォン反射モデル!
これは ランバート反射モデルに鏡面反射量を追加したモデル になります!
これは ランバート反射モデルに鏡面反射量を追加したモデル になります!

エレキベア
妙につやつやしてるクマ〜〜〜

マイケル
基本的な考え方もランバート反射モデルと同じですが、
加えて 光源から反射した向きRと頂点から視点までの向きV から鏡面反射量を計算します。
加えて 光源から反射した向きRと頂点から視点までの向きV から鏡面反射量を計算します。

マイケル
実装は下記のようになります。

エレキベア
ランバート反射モデルを理解していると簡単クマね

マイケル
パラメータについても下記のように増やして設定してあげればOKです!

マイケル
シェーダについての解説は以上になります!!

エレキベア
楽しかったクマ〜〜〜〜〜
おわりに

マイケル
というわけでfbxモデルの読込とシェーダについて解説したけど
どうだったかな?
どうだったかな?

エレキベア
シェーダと聞くと難しそうなイメージだったクマが
やってみると案外理解できたクマ〜〜〜
やってみると案外理解できたクマ〜〜〜

マイケル
シェーダいじるのは目に見える形で反映されるから楽しいよね

マイケル
さて、これで座標変換から描画まで一通り3Dゲーム開発に必要な環境は整いました!
次はいよいよ3Dゲームを開発していくのでお楽しみに!!
次はいよいよ3Dゲームを開発していくのでお楽しみに!!

エレキベア
苦労した分楽しみクマね

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

エレキベア
クマ〜〜〜〜〜〜
【C++】第四回 C++を使ったゲーム開発 〜3Dゲーム開発基礎 fbx読込とシェーダ編〜 〜完〜
※続きはこちら!