Robloxアニメーション、ヘッドレス
このマシンで初めてですか? このフォルダの
LOCAL.mdを読んでください。存在しない場合は、roblox-skills-setupスキルを実行するか(またはLOCAL.template.mdをLOCAL.mdにコピーして記入してください)。LOCAL.mdはあなたのパスとツールの場所を保持します。これはあなたのものであり、共有されることはありません。
アニメーションをデータ(時間経過に伴うポーズのJSON仕様)として作成し、それを実際の Blenderアクションにベイクし、レンダリングし、結果を確認してから信頼します。
ループは次のとおりです:作成 → 全フレームレンダリング → タイル状に並べてコンタクトシートに → 確認 → 修正 → 繰り返し。 ここにあるすべては、このループのあるステップが、他のすべてのチェックが見逃した失敗を キャッチしたために存在します。
最初に読んでください:最も時間を無駄にする罠
ほとんどのRobloxリグは、デフォルトポーズを保持するBlenderアクションを同梱しています。 Blenderは レンダリング中にそのアクションを再評価します。そのため、ポーズ値を設定してからレンダリングすると:
- すべての数値プローブはあなたのポーズが完璧に適用されたと報告します
- すべてのレンダリングフレームはリグのデフォルトポーズを示します
- データと画像は決して一致せず、エラーも発生しません
アクションをクリアしても役に立ちません。なぜなら、そのアクションがデフォルトポーズそのものだからです — クリアすると手足が胴体に崩れ落ちます。
修正方法:その同じアクションにキーフレームを挿入し、次にフレームごとにframe_set()を実行して
レンダリングします。するとアニメーションはそのアクションになります。何もそれを上書きできず、触れられていない
ボーンは定数外挿によってデフォルト値を保持し、最終的に実際のアクションが得られます — これはRobloxエクスポートに
必要なものです。scripts/anim_render.pyはすでにこれを実行します。
完全なリストはreferences/traps.mdにあります — 28個。デバッグする前に読んでください。
FKで作成。IKではありません。
RobloxのKeyframeSequenceはジョイントごとの回転のツリーであり、Motor6Dごとに1つです。
これがFKです。すべてのR15リグは、ジョイントごとに1つのコントロールボーンを同梱して一致させます。
IKターゲットでキャラクターを駆動すると、Robloxが要求していないソルバーを経由してラウンドトリップすることになり、
代償を払うことになります:
- 位置のみのIKターゲットは手足のROLLを解放するため、ブロック状のRobloxパーツはソルバーが選んだ面を 提示し、フレーム間で切り替わります。テクスチャ付きアバターでは、色が瞬時に変化するように見えます — アニメーションをバグっぽく見せる症状です
- ソルバーはフレームごとに同程度に優れたブランチ間をホッピングするため、手足が飛びますが、 すべてのフレームはまだ完全に検証されます
- 遅い
FKにはブランチ、特異点、ロールの曖昧さがなく、度単位で正確に1:1であり、 Robloxに直接エクスポートできます。
ほとんどのリグはIKモードで出荷されます。これにより、すべてのFK_*ボーンが不活性として読み取られます。
スイッチを切り替えてください — FKが死んでいると結論付けないでください:
"properties": {"ARM_IK_FK.L": 0.0, "ARM_IK_FK.R": 0.0,
"LEG_IK_FK.L": 0.0, "LEG_IK_FK.R": 0.0}
無料のコミュニティR15リグで測定され、心地よく均一です:すべての手足は真っ直ぐ下を向いて静止します。
すべてのFK_*ボーンで、X負が前方にスイング、Z正がキャラクターの右にスイング、度単位で1:1、
両側で同一 — ミラー反転はありません。子の角度は親に対して相対的です。
使用するリグに関係なく、一般的な教訓:コントロールボーンが不活性な場合、それを無効にするスイッチを探してから
諦めてください。 RigifyスタイルのR15リグは、ARM_IK_FK / LEG_IK_FKカスタムプロパティを持ち、
デフォルトで1.0(IK)です。それらを0.0に設定し、キーを打ち(frame_setがそれらを戻せないように)、
FKで作成します。上記の方向規則は1つのリグで測定されました。calibrate_rig.pyと
sweep_control.pyがあなたのリグでそれらを再測定するので、使用したことのないリグでは実行してください。
リグの.blendパスはLOCAL.mdに記載します。
手足が正確なワールドポイントに当たらなければならない場合にのみIKに手を伸ばしてください。次に罠12〜15を読んでください。
Robloxのように見せて、参照のように見せないでください
- 30 FPS、そして戦闘動作は0.3〜0.7秒実行されます。アニメーションエディタのデフォルトは 30fpsです。現実のタイミングはゲームには遅すぎます。動きが実際にどのように機能するかからメカニクスを取り、 タイミングはRobloxから取ってください。
- 5つのポーズ:アイドル、予備動作、接触、フォロースルー、回復。
- セグメントごとのイージング —
"ease": "in"で打撃に加速、"out"で落ち着かせます。 固定スムーズステップはすべてのキーフレームで減速するため、打撃は自身の接触フレームで停止するように イージングされ、全体がふにゃふにゃと読めます。 - 誇張してください。 実際のRoblox戦闘アニメーションは人間の範囲をはるかに超えて、シルエットで読めます。
- プレーングレーでレンダリング(
"plain": true)。忙しいアバターテクスチャはブロック状のリグを 読みにくいごちゃごちゃに変え、結局ポーズではなくコスチュームをデバッグすることになります。 実際のRobloxアニメーションは、まさにこの理由でプレーンなダミーで展示されます。
references/pose-recipes.mdに実際の数値があります — ガード、予備動作、チャンバー、接触、
フォロースルーの測定された角度テーブル、タイミングの骨格、そして人を捕まえる2つのルール
(肩+肘は合計約120以下に保つ;ハイキックはUpperLeg Xが−120を超える必要がある、
そうしないと脚が胴体と融合する)。それらから始めて、プレビューに対して調整してください。
再導出しないでください。
高速に — 推測ではなく測定
ループ全体は秒単位です。パスに数分かかる場合、何かが間違っています。 ミッドレンジPCで測定された、24〜36フレームの1つのアニメーション:
| ステージ | 時間 | 備考 |
|---|---|---|
| Blenderがリグをロード | 0.7秒 | スタートアップは決して問題にならない |
| 数値プローブ(FKコントロールマップ全体) | 0.1秒 | リグに数値で質問する |
プレビューレンダリング("preview": true) | 4〜6.5秒 | 1ビュー、320x240、1サンプル |
| フルレンダリング、2ビュー@640x560 | 9〜17秒 | 最後に1回だけ実行する |
| GIFエンコード | 0.3秒 | |
to_roblox.py → Luau | 0.1秒 | |
| Studioでビルド+検証 | 1回のexecute_luau呼び出し |
完成したStudio内アニメーションのためのマシン時間:1分未満。 実際に時間がかかるのは
作成の反復なので、プレビューに費やし、フルレンダリングには決して費やさないでください。
references/pose-recipes.mdから始めれば、2番目の動きは1〜3回のプレビューで決まるはずです —
references/のパンチとウェーブはどちらも最初の試行で正解でした。
"report": trueは各ビートですべてのジョイントの位置を出力します:ポーズが間違って見えるとき、
5回のレンダリングパスで推測する代わりに、1回の実行でジョイントを特定します。
プローブで答えられる質問に答えるためにレンダリングしないでください。
非妥協ルール
それぞれが、それをスキップすると見た目は良いが壊れたものが出荷されたためにここにあります:
- 終了コード0で実行されたものを決して信頼しないでください。
anim_render.pyはフレームごとにリグの 整合性をアサートし、フレームが書き込まれたことをアサートし、そうでなければ非ゼロでハード終了します。 - フレームを見てください。 毎回。
- 参照がある場合、サイドバイサイドを作成し、それで判断してください — レンダリングだけで判断しないでください。
- 完成したGIF自体を検査してください、それをエンコードしたPNGではありません。
- 赤信号を青に変えるために許容差を緩めないでください。 仕様を修正してください。
ワークフロー
1. リグをキャリブレーションする(使用したことのないリグ)
blender --background <rig>.blend --enable-autoexec --python scripts/calibrate_rig.py
blender --background <rig>.blend --enable-autoexec --python scripts/sweep_control.py -- FK_UpperLeg.R:rot TORSO:rot
calibrate_rig.pyは、デフォルメアーマチュアとコントロールアーマチュア、アクションの罠、
IK/FKスイッチの状態、そしてどのコントロールが実際に何かを動かすかを報告します。
sweep_control.pyは各軸の方向、符号、使用可能範囲を与えます — ボーンの方向と位置の両方を測定するため、
回転のみのコントロールも見逃しません。
FK_*ボーンが不活性と読み取られる場合、それはIK/FKスイッチであり、死んだリグではありません。
2. 仕様を作成する
fps、duration、w、h、margin、views、properties、plain、preview、
report、および{t, ease, bones: {Bone: {rot|loc|target|aim}}}のkeyframes[]。
rotはほとんどの場合に望むものです。エンドエフェクタのないコントロール(ROOT)にはloc。
target / aimはIKエスケープハッチです — 罠12〜15を参照してください。
忘れるたびに毎回起こる3つのこと:
- FK子の角度は親と複合します。 肩50°+肘70°は前腕を垂直から120°に配置し、肩の上を指します。 ガードでは肩+肘を約110°以下に保ってください。
- リーンとツイストは
UpTorsoにかかります。これは上半身のみを駆動します。TORSOは 脚も駆動するため、それを傾けると図形が倒れ、接地した足が滑ります。リグはまた増幅します:X = +15で頭が23°スイングします。 - 支持足首をカウンター回転させてください、
FK_Foot.X ≈ -(FK_UpperLeg.X + FK_LowerLeg.X)、そうしないと足が脚と共に傾き、キャラクターが斜面に立っているように見えます。
references/example-fk-roundhouse.json(0.8秒キック)と
references/example-fk-punch.json(0.5秒クロス)、さらにはreferences/pose-recipes.mdを参照してください。
2a. 手にプロップがある場合、それが実際にどのように保持されているかを調査してください。最初に。
このステップはキーフレームを作成する前に発生します。省略できません。 クリップに武器やツールが 含まれている瞬間、「ポーズが読めるか」はリグの問題ではなくなり、そのオブジェクトの問題になります。 これは世界に関する事実であり、行列から推測するものではありません。
これが防止するために存在する失敗、実際のビルドから:グレイブはその頭を下にして、持ち主の腰に 向けて作成されました。すべての下流ステージはその後完璧に機能しました — エンジンは作成されたグリップを再現し、 ポーズストリップはコンタクトシートとフレームごとに一致し、グリップエラー0.000、武器が体内にある サンプルゼロ — そしてゲームは逆さまに運ばれたポールアームを出荷しました。ここで作成された間違ったポーズは、 その後のすべてのチェックに対して見えません。なぜなら、その後のすべてのチェックはこれとの一致を測定しているからです。 人間が最終的に見たとき、評決はそれが逆さまであるというものでした。彼らは正しく、そのコストは ここで10秒で行われた決定の下流にあるセッション全体でした。
作成する前に:
- 武器クラスがどのように運ばれ、使用されるかを検索してください。 実践者の写真、 コンセプトアートではなく、他のゲームでもありません。10秒の読書は、数値を推測する4ラウンドよりも勝ります。
- 答えを
_intentとして仕様に書き込んでください、武器に関する文として: "頭を上に、シャフトがリーディングショルダーを横切る"、"ブレードを下げた手から上向き前方に角度をつける"。 その文がコンタクトシートの判断基準になります — ステップ4を参照してください。 - 以下のリストから明白なものを常識チェックしてください 検索に手を伸ばす前に。
| クラス | 静止時 | スイング時 |
|---|---|---|
| ポールアーム、グレイブ、なぎなた、槍 | 頭を上に - 肩に担ぐ、柄を地面に突き立てる、または刃を胸の高さ以上にしたガード。決して足元にぶら下げない | 頭が弧をリードする;シャフトは体の前で交差し、腕と同じ垂直面には決してならない |
| 剣 | 下げた手から上向き前方に角度をつけて、約+35度。真っ直ぐ下は落としたように読める | 刃がリードする;手首は蝶番ではなく、腕全体が弧を運ぶ |
| 斧、ハンマー | 頭を上にするか肩に担ぐ、重量は高く運ぶ | 頭が質量である — 最後に到着し、最も激しく到着する |
| 拳武器、ガントレット | 握るのではなく装着する;喧嘩屋のガード、両拳を上げる | 腰がそれを駆動し、肩ではない |
装着者の自分の体が入ることができるポーズでプロップを保持してください。 キャラクターの身長より長い ものを片手で運ぶ場合、腕と同じ平面には収まらないか、クリップします。
3. レンダリングして検証する
blender --background <rig>.blend --enable-autoexec --python scripts/anim_render.py -- spec.json out/
ffmpeg -start_number 0 -i "out/side_%03d.png" -vf "scale=240:-1,tile=6x6" sheet.png
カメラはアニメーション全体の境界に合わせてフレームを調整し、視野からの距離を解決するため、
何もフレームからはみ出しません;margin(デフォルト1.10)が唯一の調整ノブです。少なくとも2つの角度を
レンダリングしてください — 右足キックは左からは見えません。
次に、シートを参照と照らして判断してください。 シート自体に対してではありません。ステップ3aから_intent文を
開き、それに対してフレームごとにシートをチェックしてください:頭は上か、ブレードはリードしているか、
シャフトは体の前で交差しているか。コンタクトシートは、レンダリングが仕様と一致することを証明するだけです。
仕様が正しかったかどうかは教えてくれず、下流のすべてのステージはそれをグラウンドトゥルースとして扱います
— したがって、これがパイプラインで間違ったポーズを安価に修正できる最後のポイントです。
シートと参照が一致しない場合、参照が勝ち、仕様が変更されます。
4. GIFを配信し、次にGIFをチェックする
ffmpeg -framerate 30 -start_number 0 -i "out/side_%03d.png" -framerate 30 -start_number 0 -i "out/tq_%03d.png" -filter_complex "[0]scale=420:-1[a];[1]scale=420:-1[b];[a][b]hstack=2,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3" -loop 0 anim.gif
シートは1回、必要なサイズでそれ以上大きくせずに読んでください。 コンタクトシートは このパイプラインで最も高価なオブジェクトです:画像は同じコンテキスト内の後続のツール呼び出しごとに 再送信されるため、早期にフル解像度のシートを読むと、実行の終わりまでに数十万トークンがかかります。 タイルダウンし、問題の手足にクロップし、測定できたであろうものを再確認するために再び開かないでください。 チェックが数値にできる場合 — 武器は手を離れるか、手足を通過するか、どの角度にあるか — それを数値にして、1行のテキストを読んでください。
次に、完成したGIFからフレームを引き出して見てください — 動きは静止画とは異なって読め、 エンコード設定は静かに失敗します:
ffmpeg -i anim.gif -vf "select='not(mod(n,2))',tile=4x3" -vsync 0 verify.png
作成したクリップは、作成しなかったものを壊します
RobloxのデフォルトのAnimateスクリプトは、Core優先度でアイドル、歩行、走行、ジャンプ、落下、
登りを再生します。作成してIdle以上で再生するものはすべて、それがポーズするすべてのジョイントでそれらをマスクします、
再生されている間中。
したがって、フルボディのアイドルループ — 武器を持ったキャラクターがそこに立っている問題の正しい修正 — は、 プレイヤーが歩くときに脚の動きを停止します。なぜなら、あなたのクリップが歩行サイクルよりも高い優先度で 脚をポーズしているからです。それはまさに「歩行アニメーションがない」ように見え、作成したアイドルの キャラクターにのみ現れるため、次のように読めます
…
[翻訳のために切り詰められました]