FBXファイルの読み込み2

 FBXファイルに保存されている、アニメーションに関する情報を取り出し、ポリゴンのアニメーションを行いたいと思います。一番下のサンプルを実行すると、人型のポリゴンが奥から手前にかけて走っていきます。ここで使われるFBXファイルは、FBXファイルの読み込み1でのFBX SDKをインストールした際に、サンプルでついてくるものを使いました。このFBXファイルには、3つのアニメーションが保存されており、その内の1つを選択して再生をしています。アニメーションの指定は、AnimStackNumberという変数で指定を行っています。ここに、0~2までの数字を指定すると、それぞれの数字に対応したアニメーションが再生されます。

​ アニメーションの原理ですが、パラパラ漫画と同じです。今回は1秒間に30コマの割合で再生すると正しく再生されるように作られています。各コマのポリゴンの描画には、コマ毎にアニメーションを行うための行列を作成し、その行列を元のポリゴンの頂点データに掛け合わせることによって、形を変えていきます。以下がそのイメージになります。

各コマ毎に

​行列を掛ける

人型ポリゴンの頂点データが保存してあるFbxMeshには、頂点データの他にクラスタというデータがあります。クラスタを視覚化して見てみると、ちょうどレントゲン撮影をして写る骨のように存在しています。そのためクラスタは、ボーンやスケルトンといった言い方もされます。このクラスタの位置が変化すると、その変化に伴って、影響するポリゴンの頂点データの位置が変化していきます。

 

 各コマ毎の頂点データに掛けられる行列は、FBXファイルに最初から行列として保存されているわけではありません。行列はプログラマが作らなければいけません。行列を作るための要素はクラスタで管理されています。ここには、以下の3つの情報が保持されています。

  ・クラスタ自身が持つ行列

  ・クラスタの影響を受ける頂点のリスト

  ・影響を受ける頂点それぞれの影響度(重み)

​これらの情報を使い、各頂点に対応する行列の算出を行います。どのコマを描画するのか、コマの時間的な管理は、FbxTimeクラスで行っています。各コマ毎に変化して必要となるようなパラメータは、このFbxTimeを使って指定して取得します。

 今回のサンプルプログラムでは、いままでのプログラムと違う点が上記の計算の他にもう一点あります。それは、アニメーションを行うためにFPSを固定したことです。これまでは、DirectXのループを特に制限なく回していました。しかし、今回は元のアニメーションデータが30FPSを前提に作られていたので、ループにもその制限を施してあります。

 アニメーションのための計算構造、および固定FPSの方法について説明を行いたいと思います。

​コード解説

① アニメーションのための準備
 FBX
ファイルからアニメーションの設定、アニメーション用の時間変数の初期化を行います。

1行目から4行目で、利用するアニメーションを選び設定を行っています。2行目で、FBXファイル内にあるアニメーションの名前一覧を取得しています。3行目で、2行目で選んだアニメーションの名前を使って、そのアニメーション情報を探し出して、変数のAnimationStackへ保存しています。最後に4行目で、選んだアニメーションを設定しています。

​ 6行目から9行目では、アニメーションを実行するために必要な、時間を扱う変数の設定を行っています。startは開始時間、stopは終了時間、timeCountは開始からの経過時間、FrameTimeはアニメーション(1コマ)が実行されていく時間情報を保持ます。9行目は、時間のカウント方法を設定しています。

② アニメーションのための行列計算
 描画ループ内で何が行われているかの説明になります。

1行目から2行目で、アニメーションの時間を更新しています。もし、timeCountの時間がstop時間より経過した場合は、start時間をtimeCountに代入してリセットを行っています。

4行目から6行目では、各フレーム毎の計算に必要なパラメータの取得を行っています。8行目で宣言をしている行列の配列は、最後に全の頂点に掛け合わせるためのものです。9行目で0で初期化を行っています。

11行目のskinDeformerには、全てのクラスタ情報が入っています。14行目から25行目の間のfor分では、クラスタ一つずつを取り出して、そのクラスタ独自に持つ行列の計算を行っています。クラスタ毎に、影響を与える頂点とその数は違います。このため、19行目から24行目の内側のfor文では、

 

  20行目:影響を与える頂点の番号(インデックス)を取得

  21行目:20行目で取得した頂点に与える影響度の数値を取得

  22行目:20行目で取得した頂点に影響を与えるための行列の計算

      ( クラスタが頂点Aに影響を与える行列 = クラスタが持つ独自行列 × 頂点Aの影響度 )

​  23行目:20行目で取得した頂点に影響を与えるための行列へ加算

      ( 頂点Aに影響を与える行列 = クラスタ1が頂点Aに影響を与える行列

                     + クラスタ2が頂点Aに影響を与える行列

                     + クラスタ3が頂点Aに影響を与える行列

                     …

                     + クラスタnが頂点Aに影響を与える行列 )

ということが行われています。残りの27行目から32行目で、全ての頂点と、その各頂点に影響を与える行列を掛け合わせ、最終的な座標値を求めています。

サンプル​コード

< 動作確認環境 >
 ・Windows10 Pro
 ・Visual Studio Community 2017


基本的には空のプロジェクトを作ってもらい、以下のソースコードをコピペするだけでうまく実行できるかと思います。もしうまくいかない場合がありましたら、サンプルコードの実行に関する注意事項を一度参照してみてください。

③ FPSの固定
 これまでは、描画ループを随時走らせていたため、1秒間の間に数多くの描画更新が行われていました。この状態でアニメーションを行うことは、超高速のパラパラ漫画を見ることと同じであり、正しいアニメーションになりません。そこで、画面の描画更新を1秒間に30回行うように設定を行います。

実際に変更を行ったのは、描画ループの一番最後の行である、上記の一行です。Present関数の第一引数をこれまでの「0」から「2」へ変更しています。たったこれだけで、どうして30FPSになるのかと言うと、この第一引数は、画面のフラッシュレート(垂直同期)とフレームの表示を同期する方法を指定する所だからです。ここの値が「0」の時は、非同期であり、画面の表示の有無に関係なく即座に描画が行われます。「1」の時は、フラッシュレートと連動し、1回目の垂直同期後に表示が行われます(フラッシュレートが60Hzだった場合は1秒間に60回の描画)。「2」の時は、2回目の垂直同期後、つまり画面上の表示が2回に1回の時に描画が行われます(フラッシュレートが60Hzだった場合は1秒間に30回の描画)。

ソースコード

・FBXファイル(FBX SDKをデフォルトインストールの場合)

  C:\Program Files\Autodesk\FBX\FBX SDK\2018.1.1\samples\ViewScene\humanoid.fbx

シェーダのソースコード (shader.hlsl ※必ずこの名前で保存してください)