FreeMinecraftModelsのアニメーション
このページでは、FreeMinecraftModelsが.bbmodelまたは.fmmodelファイル内のアニメーションデータに対して実際に何を行うかを文書化しています:どの名前が特別扱いされるか、キーフレームがどのようにベイクされるか、どの補間モードとループモードが尊重されるか、そしてIKがどのように駆動されるかです。意図的に控えめな内容にしています。ここに記載されているものはすべて、インポートおよびランタイムのパイプライン上で確認できるものです。
ボーンの命名規則やインポート規約の残りの部分については、モデル作成の注意事項を参照してください。
5つのステートアニメーション
FreeMinecraftModelsは、ちょうど5つの小文字のアニメーション名を自動的なランタイムステートに紐付けます。モデル内のそれ以外のものはすべてカスタムアニメーションです。
| アニメーション名 | ループ | 再生タイミング |
|---|---|---|
spawn | しない | モデル生成時に1回。終了するとidleへ遷移します |
idle | する | 基となるエンティティの速度が0.08以下の間 |
walk | する | 基となるエンティティの速度が0.08を超えている間 |
attack | しない | トリガーされたとき。終了するとidleに戻ります |
death | しない | removeWithDeathAnimation()が呼ばれたとき |
ステートマシンの構築方法から導かれるルール:
- 開始ステートは、モデルに
spawnがあればそれ、なければidleです。どちらも持たないモデルには現在ステートが存在しないため、明示的に何かを再生するまで一切アニメーションしません。 - モデル内に存在するアニメーションだけがステートを得ます。
walkはあるがidleがないモデルは、自力でwalkから抜け出すことがありません。 - idle/walkの切り替えは基となるエンティティの速度を読み取るため、実質的に
DynamicEntityの機能です。静的エンティティとプレイヤーディスガイズにはこの用途の基となるエンティティが存在しないため、単にidleのままになります。プロップの裏側にある防具立ては動かないので、プロップもidleのままです。これら3種はいずれも、スクリプト、API、または(ディスガイズの場合は)FMM独自のディスガイズコントローラーを通じて実際のアニメーションを駆動します。
jumpは列挙値のみJUMPはAnimationStateType列挙型に存在し、walkステートもエンティティが地面を離れたときにjumpへの遷移を要求します。しかしjumpステートは一切登録されないため、その要求は何も起こしません。ただしjumpという名前のアニメーションが無効というわけではありません。単に他のカスタムアニメーションと同じように振る舞い、手動でトリガーする必要があるだけです。プレイヤーディスガイズは例外で、jumpが実際に組み込まれている別のコントローラーを使用します。
プレイヤーディスガイズは別のセットを使用します
プレイヤーディスガイズは上記のステートマシンを実行しません。独自のティック単位コントローラーを持ち、5つの予約名(attack、jump、sneak、walk、idle)をこの優先順位で評価します。また、モデルにidleがない場合はコンソールに警告を出します。完全な表と単発再生のタイミングに関する注意点は、プレイヤーディスガイズを参照してください。
カスタムアニメーション
上記5つ以外の名前を持つアニメーションも、名前を指定して再生できます:
modeledEntity.playAnimation("open", /* blend */ true, /* loop */ false);
modeledEntity.stopCurrentAnimations();
boolean exists = modeledEntity.hasAnimation("open");
context.prop:play_animation("open", true, false)
context.prop:stop_animation()
- **
blend**はクロスフェードを行いません。trueは現在のステートのティックが完了した後に開始するようアニメーションをキューに入れ、falseは割り込んで即座に切り替えます。 - **
loop**はカスタムアニメーションにのみ適用されます。組み込みステートは、何を渡しても自身のループ設定を使用します。 - ループしないカスタムアニメーションが終了すると、エンティティは最後にコミットされた組み込みステート(直前に行っていた動作)に戻ります。それが存在しない場合は
idleに戻ります。 - 名前が登録済みステートにもモデル内のアニメーションにも一致しない場合、
playAnimationはfalseを返します。 stopCurrentAnimations()は、モデルにidleがあればそこへ遷移します。ない場合は現在のステートを抜け、アクティブなアニメーションがない状態のままになります。- カスタムアニメーションの再生中は、
attack、attack_melee、attack_rangedの要求は握りつぶされます。これは、通常の戦闘によってスクリプト化されたシーケンスが中断されないようにするためです。
タイミングと再生時間
- Blockbenchはアニメーションの長さを秒で保存します。FMMはこれを
ceil(秒 x 20)で変換するため、再生時間は常に整数ティックとなり、短いアニメーションは切り捨てではなく切り上げられます。 - すべてのアニメーションは、インポート時にティックごとのフラットなフレーム配列にベイクされます。再生はティックごとの配列参照であり、リアルタイム補間ではありません。
- ループするアニメーションは
counter % durationでインデックスを取り、ループしないものは最終フレームでクランプされ、それ以降は変化の描画を停止します。 - キーフレームの時刻は小数のティック位置を保持する(
20 x timeであり丸めません)ため、0.37秒のキーフレームはティックの間に位置し、スナップされたり破棄されたりせず正しく補間されます。アニメーションの最終キーフレームも丸めによって切り捨てられることなく保持されます。 - 同じチャンネル上の2つのキーフレームがまったく同じ時刻に位置する場合、ファイル順で後のものが優先されます。
- 時刻が有限でないキーフレームはそのトラックを中断させ、アニメーションごとに1回だけ
Malformed animation timeline for model ...という警告を出しますが、モデルの他のアニメーションは変換され続けます。
長さ0のアニメーションは有効です
長さが0(または負の値)のアニメーションは、意図的な静止ポーズとして扱われます。これは、「アニメーションなし」という名前付きエントリを必要とする家具やその他のプロップでよく使われるオーサリング上の選択です。警告なしで静かにスキップされ、フレームを一切生成しません。
ループモード
Blockbenchのループ設定はアニメーションから直接読み取られます:
| Blockbenchのループモード | Javaランタイム | Bedrockエクスポート |
|---|---|---|
loop | 無限に繰り返します | "loop": true |
once | 最後まで再生して停止します | "loop": false |
hold | 最後まで再生し、最終フレームを保持します | "loop": "hold_on_last_frame" |
補間タイプ
各キーフレームは独自の補間タイプを持ち、あるキーフレームへ向かう区間はそのキーフレームのタイプを使用します。サポートされているのは4種類です:
| Blockbenchのタイプ | FMMでの挙動 |
|---|---|
linear | 単純な線形補間 |
catmullrom | 滑らかな補間(イーズイン/イーズアウト) |
bezier | 固定の0.42/0.58制御点で近似します。FMMはキーフレームごとのベジェハンドルを読み取りません |
step | 次のキーフレームまで直前の値にスナップします |
このセット以外のものは解析に失敗し、不正なタイムラインとして報告されます。
アニメーションされるチャンネル
ボーンごとに3つのチャンネル、回転、位置、スケールがベイクされます。オーサリング時に重要となる注意点:
- 位置の値は16で除算されます(Blockbenchのピクセルからブロックへ)。
- 回転の値はラジアンに変換されます。
- Blockbenchの
format_version5以降では、X・Y回転およびX位置の符号が反転します。 FMMは宣言されたフォーマットバージョンに基づいて自動的に補正するため、手作業で補正しないでください。ただし、v5の宣言とv4形式のデータを混在させることも避けてください。 - あるチャンネルにキーフレームがないボーンは、そのチャンネルの静止値を維持します。あるティックにフレームがまったくないボーンは、回転
0,0,0、移動0,0,0、スケール1,1,1にリセットされます。 - キーフレームのデータ値は
.bbmodel内で文字列として記述されている場合があります。FMMはこれを単なる数値として解析します。空文字列はスケールでは1、それ以外では0になり、解析できない値はFailed to parse supposed number value ...をログに出力して0になります。Molang式は評価されません。 - 読み取られるのはキーフレームの最初のデータ値のみです。そのため、stepキーフレームでBlockbenchが持つpre/postの個別値は1つに統合されます。
アニメーションされないもの
hitboxボーン。これを対象とするアニメーショントラックは完全にスキップされます。- Blockbenchのエフェクトトラック(サウンド、パーティクル、タイムラインインストラクションのアニメーター)。タイプが
boneまたはnull_objectでないアニメーターはすべて無視されるため、FMMがアニメーションタイムラインからサウンドやパーティクルを発生させることはありません。代わりにLuaスクリプトや独自のプラグインから駆動してください。 - 名前で解決できなかったボーン。存在しないボーンを指すトラックは
Failed to get bone <name> from model <model>!をログに出力してスキップされます。
インバースキネマティクス(IK)
Blockbenchのnullオブジェクトは、IKコントローラーとして機能します。FMMはランタイムでチェーンをFABRIK(Forward And Backward Reaching Inverse Kinematics)により解き、最大10回の反復と0.001の許容誤差で打ち切ります。
構成要素の関係:
ik_source(チェーンのルートボーン)とik_target(末端のボーンまたはロケーター)の両方を持つnullオブジェクトがチェーンを定義します。チェーンはターゲットからソースへ向かって階層を遡ることで検出されます。- 読み取られるのはnullオブジェクトの位置キーフレームのみです。これらはコントローラーの静止位置を基準としたフレームごとのゴールオフセットになります。nullオブジェクト上の回転およびスケールのトラックは無視されます。
- 毎ティック、現在のフレームのゴールオフセットが適用されチェーンが解かれます。IKデータのないフレームでは、代わりにチェーンのIK回転がクリアされます。
- nullオブジェクトの
lock_ik_target_rotationはモデルから読み取られます。
解決できなかったチェーンは、名前付きのコンソール警告とともにスキップされます。正確なメッセージとオーサリング上の制約については、モデル作成の注意事項を参照してください。
Bedrockエクスポート
変換された各モデルは、生成されるバンドル内のanimations/<model_id>.animation.jsonにBedrock用アニメーションファイルも書き出します:
- アニメーション識別子は
animation.fmm.<model_id>.<animation_name>で、名前はBedrock向けにサニタイズされます。 animation_lengthは秒単位の再生時間で、最小値は0.05です。これにより1ティックのアニメーションも有効なままになります。- ループモードはループモードの表の通りにマッピングされます。
- アニメーションがまったくないモデルにも、Bedrockのエンティティ定義が有効であり続けるよう、何もしない
idleエントリが1つ生成されます。 - エクスポートされるのは表示用のボーンのみです。
hitbox、自動生成されるfmm_nametag_bone_*ネームタグボーン、およびm_マウントポイントボーンはジオメトリから除外され、したがってアニメーションのボーンブロックからも除外されます。自分で作成したtag_ボーンは除外されません。他のボーンと同じようにエクスポートされます(通常はキューブを持たない空のボーンとして)。除外されるのは、そこから生成されたネームタグ側のボーンだけです。 - アニメーションごとに1つのアニメーションコントローラーが生成され、エンティティプロパティによって切り替えられます。これがFMMがBedrockクライアント上で特定のアニメーションを再生する仕組みです。
バンドルがディスク上のどこに配置されるかについては、リソースパック出力を参照してください。
他のシステムからアニメーションを再生する
| 呼び出し元 | エントリポイント |
|---|---|
| プラグイン(Java) | ModeledEntity#playAnimation(String, boolean blend, boolean loop) / #stopCurrentAnimations() / #hasAnimation(String) |
| プロップのLuaスクリプト | context.prop:play_animation(name, blend, loop) / context.prop:stop_animation() |
| 任意のLuaエンティティテーブル | entity.model:play_animation(name, blend, loop) / entity.model:stop_animations()(entity.is_modeledがtrueのときに利用可能) |
周辺のインターフェースについては、API&開発者ガイドおよびLua:プロップ&アイテムAPIを参照してください。
トラブルシューティング
アニメーションが自動的に再生されません。
自動的に発火するのはspawn、idle、walk、attack、deathだけです。それ以外はすべて明示的なplayAnimation/play_animationの呼び出しが必要です。
モデルがまったく動きません。
おそらくspawnもidleも持っていないため、生成時にどのステートにも入っていません。idleを追加してください。
アニメーションは再生されるのに何も動きません。 アニメーションの長さを確認してください。長さ0のアニメーションは静止ポーズとして扱われ、仕様として警告なしにスキップされます。
回転が反転しています。
.bbmodel内のmeta.format_versionを確認してください。FMMはフォーマットバージョン5以降でX・Y回転の符号を反転します。あるバージョンを宣言しながら別バージョンの形式のデータを持つファイルは、反転した状態で出力されます。
コンソールにMalformed animation timeline for model ...と表示されます。
そのアニメーション内の1つのトラックが読み取りまたは補間できませんでした。警告はアニメーションごとに1回発生し、関係するボーンまたはIKコントローラー名を示します。モデルの他のアニメーションは引き続き変換されます。
Blockbenchのタイムラインに置いたサウンドやパーティクルが何も起きません。 エフェクトトラックはインポートされません。Luaスクリプトまたは独自のプラグインからトリガーしてください。