サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

3D アニメーションとスキン処理

Model (と ModelInstance) には1つ以上のアニメーションを含めることができます。 アニメーションとは、モデル内の複数のノードに適用される変換処理のシーケンス(キーフレーム)です。 各アニメーションはその名前(id)によって識別されます。名前(id)はモデル内で重複があってはいけません。 例えば、"walk" という名前のアニメーションと"attack"という名前のアニメーションを持つキャラクターがいるかもしれません。 このページでは、アプリケーション内にアニメーションを読み込んでで使用する方法について説明します。

スキン処理を使って、1つ以上のノードの変換情報に基づいてmodel (mesh)を変形させることができます。 スキン処理は通常、アニメーションと組み合わせて使用されます。 このページでは、アプリケーション内でスキン処理を使用する方法についても説明します。



アニメーションを読み込む

fbx-conv を使ってモデルをFBX から G3DB/G3DJへ変換する時、それに合わせてアニメーションも自動的に変換されます。 FBXと同じ様に、G3DB/G3DJファイルでは1つのファイル内に他のモデルデータと一緒に複数のアニメーションを含めることができます。 ソースFBX ファイルに存在しないノードに適用されるアニメーションは変換されません。 そのため、FBXへエクスポートする時には全てのノードとアニメーションを選択するようにしてください。

G3DJ ファイル形式に変換してそれをご使用のテキストエディタで開くことで、変換されたアニメーションを確認できます。 アニメーションはファイルの最下部にあります。 アニメーション(キーフレーム)によってファイルのサイズが大きくなる可能性があるので注意してください。 そのため、製品版ではサイズの小さいG3DB ファイル形式を使用することをお勧めします。

LibGDX はキーフレーム間のカスタム補間をサポートしていません。 線形補間以外の補間方法を使用する場合、fbx-convはこれを補うために追加のキーフレームを生成します。 この補間処理は対象FPSに従って行われます。 対象FPS はFBXでカスタマイズ可能ですが、全てのモデリングソフトでこの値を変更できるわけではありません(既定値は30 FPS)。 追加キーフレームによってファイルのサイズが増えるのを防ぐために、可能であれば線形補間を使用するようにしてください。

G3dModelLoader やAssetManagerを使ってG3DB/G3DJファイルを読み込んだ時、アニメーションも読み込まれます。 ModelからModelInstance を作成する時、アニメーションもModelInstanceへコピーされます。 ModelInstanceを作成する時に特定のノードを指定した場合、そのノード (と子ノード)に適用されるアニメーションのみが新規ModelInstanceへコピーされます。



アニメーションを使用する



1つのアニメーションを適用する

アニメーションを ModelInstanceへ適用するためには、 AnimationControllerを作成します。 AnimationController は1つのModelInstance 専用のもので、ModelInstance はAnimationControllerより長く生存しなければなりません。 AnimationController を使って、一度に1つのアニメーションをModelInstance へ渡すことができます。 AnimationController は複数アニメーション間のブレンド処理(=遷移処理)をサポートしています。 同一のModelInstanceに複数のアニメーションを適用したい場合は、アニメーションがお互いに干渉しない(同じノードに対して処理を行わない)のであれば、複数のAnimationControllersを使用できます。

アニメーションが設定されている時(後述)、AnimationControllerはフレーム毎に更新する必要があります。 これは AnimationController.update(float delta)メソッドを使って行うことができます。 delta 引数は、最後にupdateが呼び出されてからどれくらいの時間が経過したかをAnimationControllerへ通知するために使用します。 一般的に、その引数の値にはGdx.graphics.getDeltaTime() が使用されます。

現在のアニメーションを設定するには、setAnimation(String id) メソッドを使用します。 これを実行するとアニメーションは即座に再生されます(もし現在のアニメーションが既に設定されていたら、それは削除されます)。 id引数は、ModelInstance内に存在するアニメーションの名前でなければなりません(大文字と小文字は区別されます)。

ModelInstance instance;
AnimationController controller;
public void create() {
    ...
    instance = new ModelInstance(model);
    controller = new AnimationController(instance);
    controller.setAnimation("walk");
}
public void render() {
    ...
    controller.update(Gdx.graphics.getDeltaTime());
    ...
}

setAnimation(String id) メソッドはアニメーションを通常の速度で一回再生し、そして停止します(アニメーションは最後のフレーム絵の状態で止ります)。 アニメーションを削除するには(so the nodes are at their original transformation)、 setAnimation(null)を呼び出します。



ループ処理

アニメーションを複数回実行したい場合、 setAnimation(String id, int loopCount)メソッドが使用できます。 loopCount 引数を使ってアニメーションが再生される回数を指定できます(0は設定できません)。 アニメーションをループし続けるには、 -1の値を設定します。



AnimationDesc

アニメーションの全てのメソッドは (setAnimation(...)のような) 、 AnimationDesc インスタンスを戻り値として返します。 これは、アニメーションが再生している間(もしくは再生キューに入れられている間。詳細は後述) は有効です。 AnimationDescにはアニメーションに関する全ての情報が含まれています。現在のアニメーション時間やアニメーションの残りループ回数などです。 これらの値を変更して実行中のアニメーションを制御することができます。 アニメーションが終了したら、AnimationDescへの全ての参照を削除する必要があります。AnimationDescが次のアニメーションで再利用(プール)されるかもしれないからです。



AnimationListener

アニメーションがループした時、または終了した時に通知を受け取るには、 AnimationListenerインタフェースを実装します。 AnimationListenerインタフェースでは、アニメーションが終了したりループした時に通知がされます。 その際、終了またはループしたアニメーションのAnimationDescを受け取ります。 全てのアニメーションメソッドでは、AnimationListenerを引数として渡すことができます。例えば、setAnimation(String id, int loopCount, AnimationListener listener)



アニメーションをブレンドする

setAnimationを使ってアニメーションを切り替えた時、前のアニメーションは突然停止されます。 前のアニメーションを新しいアニメーションにブレンドして、アニメーション間の遷移をスムーズにすることができます。 これにはanimate(...)を使用します。 animate メソッドは、setAnimation メソッドと同じ引数に加えて追加でtransitionTime引数を受け取ります。 遷移の間は新しいアニメーションは古いアニメーションの上で線形補間され、その結果として遷移がスムーズになります。 前のアニメーションがない場合、新しいアニメーションは即座に開始されます。



アニメーションをキューに入れる

現在のアニメーションが完了した時に新たにアニメーションを開始するには、queue(...) メソッドを使用します。 現在のアニメーションが連続してループしている場合、キューに入れられたアニメーションは現在のループが完了した時に実行されます。 そうでない場合、キューに入れられたアニメーションは現在のアニメーションが終了した時(残り全てのループを含む)に実行されます。 現在のアニメーションがない場合、キューに入れられたアニメーションは即座に実行されます。 遷移時間が0以上に設定されている場合、キューに入れられたアニメーションはブレンド処理されます。



アクションアニメーション

アクションアニメーションとは、現在のアニメーションの上で実行される(一般的には短い)アニメーションです。 In practice, it is the same calling animate(...) with the action animation and calling queue(...) with the previous animation.



アニメーション速度

全てのアニメーションメソッド (setAnimationanimatequeueactionのような)ではそのアニメーションの速度を設定できます。 速度は "seconds per second"として定義します。 そのため1の値ではアニメーションを通常の速度で再生します。 値が1より大きいと、アニメーションを速めに再生します(例えば、値が 2だと元の2倍の速さでアニメーションを実行します)。 値が1より小さいと、アニメーションを遅めに再生します(例えば、値が 0.5だと元の半分の速さでアニメーションを実行します)。 速度には負の値を設定できます。そうすると、アニメーションは逆再生されます。

個々のアニメーションを速度を制御できる一方、AnimationControllerの update(float delta) メソッドのdelta引数を変更することで全てのアニメーションの全体的な速度を制御することもできます。 例えば、controller.update(0.5f * Gdx.graphics.getDeltaTime());を実行した場合は、全体的な速度は元の速度の半分になります。 delta 引数を負の値にすることもできます、そうすると、全てのアニメーションは逆再生されます。



ノードの変形

アニメーションを実行している間は、影響を受ける全てのノードのisAnimatedメンバにはtrueが設定されます。 これによりノードのtranslation値とrotation 値とscale 値は使用できなくなります。したがってアニメーション中は、影響を受けるノードをあなたの手で変形することはできません。



スキン処理

スキン処理を使って、一つ以上のノード(bones や jointsとも呼ばれます)の変換情報に従ってモデルを変形することができます。 最も一般的にスキン処理が使用されるのは、目に見えないノード(NodePartsが取り付けられていないノード)を使ってモデルを変形する時です。 これらのノード(一般的には階層を形成している)は、スケルトンやアーマチュアとも呼ばれます。

実際にスキン処理を使用している時、モデルは目に見えないスケルトンパーツ(1つ以上のノード)と目に見えるパーツ(1つ以上のノード)を持っています。 目に見えるノード自体は変形しませんが、スケルトンは変形されるので(例えばアニメーションによって)、結果として目に見えるメッシュの頂点の位置に影響を与えます。

これは、ブレンドウェイト(ボーンウェイトとも呼ばれます。)を使って行います。ブレンドのウェイトとは、表示されるノードの頂点属性です。 各ブレンドウェイトはインデックス(特定のボーンやノードの)とウェイト(そのボーンやノードによってどれくらい影響を受けるか)を持っています。 各表示ノード(NodePart)はそのボーン(スケルトンのノード)への参照を持っています。



スキンを読み込む

LibGDX ではスキンシェーダのみをサポートしています。スキンシェーダには少なくとも Open GL ES 2.0が必要です。 モデリングソフトを使ってスキン処理したモデルを作成してそれをFBX へエクスポートしてG3DB/G3DJに変換した場合、スキン処理は綺麗に動作するでしょう。 アニメーションと一緒に、表示ノードと非表示ノード(スケルトン)を両方ともエクスポートする必要があるので忘れないでください。

スキン処理でベストかつ最適な結果をえるには、いくつか調整をする必要があります。 既定では、fbx-convでは頂点ごとに4つのボーンウェイトを持っています(各頂点は多ければ四つのノードの影響を受ける可能性があります)。 また、既定では fbx-convは、頂点に影響を与えるボーンの合計が12を超える場合には、同じボーンを共有する頂点をグループ化してメッシュを複数のパーツに分割します。

メッシュの分割が行われるのは、シェーダーが使用できる変数の量に制限があるためです。 しかし、その結果として描写呼び出しが複数回行われ、パフォーマンスに影響を与える可能性があります。 これの詳細情報については、この投稿を参照してください。

コマンドラインオプション-w-bを使用することで、 fbx-convの既定値を変更できます。 -w コマンドを使うと、1つの頂点に影響を与えるボーンの数を指定できます。 範囲は1から8の間でなければなりません(デフォルトのシェーダーは8を超えるボーンウェイトをサポートしていません)。 通常は、可能な限りこれを低く保つようにしてください。


fbx-conv -w 3 inputfile.fbx

-b コマンドを使用することで、fbx-convがメッシュの分割を開始する前に、許容されるボーンの合計を指定できます。 この値は0より大きい値にしなければならず、ハード制限はありません。 通常この値は、-w コマンドで指定した数の3倍を下回る値に設定すべきではありません。 You can increase the value to avoid splitting the mesh, but at the cost of shader uniforms.


fbx-conv -b 16 inputfile.fbx

-b コマンドラインオプションを使ってボーンの最大数を変更する場合、シェーダーも同じ値を使用するように変更する必要があります。 これは、ModelBatchのShaderProvider を作成する際にConfig#numBonesメンバを使用することで行うことができます。 例えば:

DefaultShader.Config config = new DefaultShader.Config();
config.numBones = 16;
modelBatch = new ModelBatch(new DefaultShaderProvider(config));