FreeMinecraftModels 動畫
本頁記錄 FreeMinecraftModels 實際上如何處理 .bbmodel 或 .fmmodel 檔案中的動畫資料:哪些名稱是特殊的、關鍵影格如何被烘焙、支援哪些插值與循環模式,以及 IK 是如何被驅動的。本頁刻意保守 —— 這裡的一切都能在匯入與運行時管線中看到。
關於骨骼命名規則與其餘的匯入契約,請參閱模型製作注意事項。
五個狀態動畫
FreeMinecraftModels 只把五個小寫動畫名稱綁定到自動的運行時狀態。模型中的其他一切都是自訂動畫。
| 動畫名稱 | 是否循環 | 何時播放 |
|---|---|---|
spawn | 否 | 模型建立時播放一次。結束後會接續到 idle |
idle | 是 | 當底層實體的速度小於或等於 0.08 時 |
walk | 是 | 當底層實體的速度大於 0.08 時 |
attack | 否 | 被觸發時播放;結束後回到 idle |
death | 否 | 呼叫 removeWithDeathAnimation() 時 |
由狀態機的建構方式推導出的規則:
- 若模型有
spawn,起始狀態就是spawn,否則為idle。兩者皆無的模型沒有目前狀態,因此在明確播放某個動畫之前不會有任何動作。 - 只有模型中實際存在的動畫才會取得狀態。一個有
walk但沒有idle的模型,永遠不會自行從walk轉換出來。 - idle/walk 的切換讀取的是底層實體的速度,因此這實際上是
DynamicEntity的功能。靜態實體與玩家偽裝在此並沒有底層實體,因此就停留在idle;道具背後的盔甲架不會移動,所以道具也停留在idle。這三者都是透過腳本、API,或(對偽裝而言)FMM 自己的偽裝控制器來驅動真正的動畫。
jump 只存在於列舉中JUMP 確實存在於 AnimationStateType 列舉中,而且當實體離地時 walk 狀態也的確會請求一次 jump 轉換 —— 但由於從未註冊任何 jump 狀態,該請求最終不會有任何結果。名為 jump 的動畫並非無效:它只是表現得跟其他自訂動畫一樣,必須手動觸發。玩家偽裝是例外 —— 它們使用另一個控制器,其中的 jump 確實有被接上。
玩家偽裝使用另一組名稱
玩家偽裝不會執行上述的狀態機。它有自己的每 tick 控制器,並保留五個名稱 —— attack、jump、sneak、walk、idle —— 依該優先順序評估;如果模型沒有 idle,它會在主控台發出警告。完整表格與一次性動畫的時序注意事項請見玩家偽裝。
自訂動畫
任何名稱不屬於上述五個之一的動畫,仍可依名稱播放:
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會把動畫排入佇列,等目前狀態的該 tick 完成後才開始;false則會中斷並立即切換。loop僅適用於自訂動畫。內建狀態一律使用自己的循環設定,不論你傳入什麼值。- 當非循環的自訂動畫結束時,實體會回到最後一個已提交的內建狀態(也就是它先前正在做的事),若先前沒有狀態則回到
idle。 - 當名稱既不符合任何已註冊狀態、也不符合模型中的任何動畫時,
playAnimation會回傳false。 - 若模型有
idle,stopCurrentAnimations()會轉換到idle;否則它會退出目前狀態,讓模型沒有任何作用中的動畫。 - 在自訂動畫執行期間,對
attack、attack_melee或attack_ranged的請求會被吞掉,以免腳本化的序列被例行戰鬥打斷。
時序與長度
- Blockbench 以秒為單位儲存動畫長度。FMM 以
ceil(seconds x 20)轉換它,因此長度一律是整數個 tick,短動畫會無條件進位而非捨去。 - 每個動畫都會在匯入時被烘焙成一個扁平的逐 tick 影格陣列。播放是每 tick 一次的陣列查找,而非即時插值。
- 循環動畫以
counter % duration取索引;非循環動畫則鉗制在最後一個影格,之後不再渲染任何變化。 - 關鍵影格時間會保留其小數的 tick 位置(
20 x time,不四捨五入),因此位於 0.37 秒的關鍵影格會落在兩個 tick 之間並被正確插值,而不會被吸附或丟棄。動畫的最後一個關鍵影格會被保留,不會因四捨五入而被截掉。 - 若同一通道上有兩個關鍵影格落在完全相同的時間,檔案順序中較後者勝出。
- 時間為非有限值的關鍵影格會中止該軌道,並針對每個動畫產生一則
Malformed animation timeline for model ...警告,而該模型的其他動畫仍會繼續轉換。
零長度動畫是有效的
長度為 0(或負數)的動畫會被視為刻意的靜態姿勢 —— 這是家具與其他需要一個具名「無動畫」條目的道具常見的製作選擇。它會被靜默略過且不發出警告,也不會貢獻任何影格。
循環模式
Blockbench 的循環設定會直接從動畫讀取:
| Blockbench 循環模式 | Java 運行時 | Bedrock 匯出 |
|---|---|---|
loop | 無限重複 | "loop": true |
once | 播放完畢後停止 | "loop": false |
hold | 播放完畢後停在最後一個影格 | "loop": "hold_on_last_frame" |
插值類型
每個關鍵影格都帶有自己的插值類型,而進入某個關鍵影格的區段會使用該關鍵影格的類型。支援四種:
| Blockbench 類型 | 在 FMM 中的行為 |
|---|---|
linear | 直接的線性插值 |
catmullrom | 平滑插值(緩入/緩出) |
bezier | 以固定的 0.42 / 0.58 控制點近似 —— FMM 不會讀取個別關鍵影格的貝茲控制桿 |
step | 吸附到前一個值,直到下一個關鍵影格 |
超出這組範圍的任何內容都會解析失敗,並被回報為格式錯誤的時間軸。
有動畫的通道
每個骨骼會烘焙三個通道:旋轉、位置與縮放。製作時值得注意的事項:
- 位置值會被除以 16(Blockbench 像素轉方塊)。
- 旋轉值會被轉換成弧度。
- Blockbench
format_version5 及以上會翻轉 X 與 Y 旋轉以及 X 位置的正負號。 FMM 會依據宣告的格式版本自動補償,因此請不要手動修正 —— 但也不要把 v5 的宣告與 v4 形式的資料混在一起。 - 某個通道上沒有關鍵影格的骨骼,會在該通道保持其靜止值;在某個 tick 完全沒有影格的骨骼,則會被重設為旋轉
0,0,0、位移0,0,0、縮放1,1,1。 - 關鍵影格資料點在
.bbmodel中可能被寫成字串。FMM 會把它們當成純數字解析 —— 空字串對縮放而言變成1,其他情況變成0;無法解析的內容會記錄Failed to parse supposed number value ...並變成0。Molang 運算式不會被求值。 - 每個關鍵影格只會讀取第一個資料點,因此 Blockbench 在 step 關鍵影格上分開的 pre/post 值會收攏成一個。
哪些東西不會有動畫
hitbox骨骼。指向它的動畫軌道會被直接略過。- Blockbench 的效果軌道(音效、粒子與時間軸指令動畫器)。任何類型不是
bone或null_object的動畫器都會被忽略,因此 FMM 不會從動畫時間軸觸發音效或粒子。請改以 Lua 腳本或你自己的外掛來驅動它們。 - 無法依名稱解析的骨骼。指向不存在骨骼的軌道會記錄
Failed to get bone <name> from model <model>!並被略過。
逆向運動學(IK)
Blockbench 的空物件會作為 IK 控制器。FMM 在運行時以 FABRIK(Forward And Backward Reaching Inverse Kinematics)求解鏈,上限為 10 次迭代、容差為 0.001。
各部分如何搭配:
- 同時具有
ik_source(鏈的根骨骼)與ik_target(末端骨骼或定位器)的空物件會定義一條鏈。該鏈是從目標往上走訪階層直到來源而被找出來的。 - 只會讀取空物件的位置關鍵影格。它們會成為相對於控制器靜止位置的每影格目標偏移;空物件上的旋轉與縮放軌道會被忽略。
- 每個 tick 都會套用目前影格的目標偏移並求解該鏈。在沒有 IK 資料的影格上,該鏈的 IK 旋轉會被清除。
- 空物件上的
lock_ik_target_rotation會從模型中讀取。
無法解析的鏈會被略過,並附帶一則具名的主控台警告 —— 確切訊息與製作限制請見模型製作注意事項。
Bedrock 匯出
每個被轉換的模型也會在產生的套件內寫入一份 Bedrock 動畫檔案,位於 animations/<model_id>.animation.json:
- 動畫識別碼為
animation.fmm.<model_id>.<animation_name>,名稱會針對 Bedrock 做淨化處理。 animation_length是以秒為單位的長度,下限為0.05,因此一個 tick 的動畫仍然有效。- 循環模式的對應方式如循環模式表格所示。
- 沒有任何動畫的模型仍會取得一個什麼都不做的
idle條目,讓 Bedrock 實體定義維持有效。 - 只有視覺骨骼會被匯出。
hitbox、自動生成的fmm_nametag_bone_*名稱標籤骨骼,以及m_騎乘點骨骼都會被排除在幾何體之外,因此也被排除在動畫骨骼區塊之外。你自己製作的tag_骨骼不會被排除 —— 它會像其他骨骼一樣被匯出(通常是一個沒有立方體的空骨骼);被濾掉的只有它所生成的名稱標籤對應骨骼。 - 每個動畫都會產生一個動畫控制器,並由實體屬性切換,這就是 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。
我的動畫有播放,但什麼都沒動。 請檢查動畫長度。零長度動畫依設計會被視為靜態姿勢並被靜默略過。
旋轉是鏡像的。
請檢查 .bbmodel 中的 meta.format_version。FMM 會為格式版本 5 及以上翻轉 X/Y 旋轉的正負號;宣告某個版本卻攜帶另一版本資料的檔案,出來的結果就會是鏡像。
主控台顯示 Malformed animation timeline for model ...。
該動畫中有一條軌道無法被讀取或插值。這則警告在每個動畫只會出現一次,並指出牽涉到的骨骼或 IK 控制器;該模型的其他動畫仍會正常轉換。
我的 Blockbench 時間軸中的音效與粒子沒有作用。 效果軌道不會被匯入。請改從 Lua 腳本或你自己的外掛觸發它們。