ほげたつブログ

プログラムとアニメーションをかじって生きてる

UE4.26 Control Rig における IK ノードまとめ

こちらは「Unreal Engine 4 (UE4) Advent Calendar 2020」3日目の記事です。✌︎('ω'✌︎ )

qiita.com

UE4.26 でのアニメーション関連機能

UE4.26 正式版のリリースが待ち遠しいです。リリースノート を読んでいますが、アニメーション関連機能として目を引くのは Full Body IK (Beta) の実装ですね。今回は Control Rig で利用できる IK 機能に絞り、既存ノードのプロパティとアルゴリズムについて見ていこうと思います。ちなみに標準実装されている機能は知識が無くても使いやすい形で実装されているため、必ずしも内部実装を知っておく必要は無いのですが、直感的でない動作をした場合に解決の糸口を見つけやすいという利点があるので頭の片隅に置いておくと役に立つかもしれません。

Control Rig について

まだ Control Rig を履修していない方はおかずさんの入門スライドから読むことをオススメします。猫でもわかります。目指せ猫。

www.slideshare.net

f:id:hogetatu:20201130000121j:plain

全く関係ないですが十三機兵防衛圏は神ゲーなのでやりましょう。


検証環境

UE4.26 Preview 7 で検証しています。特に Fullbody IK ノードについてはベータ版という事もあり、不具合のように見える挙動がいくつかあるので現時点では参考程度にして下さい。

また、この記事内では Control Rig のノードで使用されている呼称に合わせてボーンやコントローラ、スペースといった入力を Item と表記しています。

Basic IK (Two Bone IK)

youtu.be

プロパティ名 詳細
Item A 第一関節として扱う Item
Item B 第二関節として扱う Item
Effector Item 末端として扱う Item
Effector 末端の到達目標位置/回転
Primary Axis 関節の正面方向
Secondary Axis 関節の上方向(肘の内向き方向)
Primary Axis 関節の正面方向
Pole Vector 第二関節を回転させる時の基準方向/位置
Pole Vector Kind Pole Vector の種類(方向もしくは位置)
Pole Vector Space Pole として扱う Item
Propagate to Children 補正後に子ボーンにも変更を反映するか


Basic IK は Tow Bone IK とも呼ばれ、伸び縮みしない剛体を二つの関節で接続した状態において、末端位置から各関節の回転値を計算するものです。これは一般的な生物の腕の構造に近く、シンプルで制御しやすいので最も使う機会が多いと思います。

Pole というのは第二関節を曲げる際に、どの方向に曲げるのかを決定するためのナビゲータです。Pole Vector Kind に Location を指定し、Pole Vector Space にコントローラを指定すると制御がしやすいです。ノードを選択すると Debug Settings を有効にするチェックボックスがあるので、こちらにチェックを入れると Pole に向かって肘が曲がっているのがわかりやすいかと思います。

f:id:hogetatu:20201122210721p:plain

また、実行ピン (Execute) が無いだけで同じアルゴリズムの Basic IK Transforms / Basic IK Positions というノードも存在します。特別な理由が無い限りは素直に実行ピン付きを使うのが良いと思います。

Basic FABRIK (Forward and Backward Reaching IK)

youtu.be

プロパティ名 詳細
Items 関節リスト
Effector Transform 末端の到達目標位置/回転
Precision 反復(イテレーション)を終了する末端 Item と Effector の距離閾値
Max Iterations 最大イテレーション回数
Propagate to Children 補正後に子ボーンにも変更を反映するか


FABRIK は Forward and Backward Reaching IK の略称で、Effector を移動させる際に各関節の位置情報から最終的な関節位置を先に決定し、それに合わせて各関節を回転させる手法です。逆行列計算を必要としないので少ない計算コストで近似的な解が得られるのが特徴です。反復する手法なのでイテレーション回数を増やせば精度は上がりますが、最大イテレーション数が多め且つ収束しない場合に計算コストが上がってしまいます。とは言っても計算自体が単純なベクトル演算のみなので、現実的な回数に設定しておけば問題になることは少ないです。

アルゴリズムについて詳しく知りたい場合は 著者のサイト から論文やチュートリアル動画がリンクされています。この記事でも簡単にアルゴリズムについて解説しておきます。

f:id:hogetatu:20201129180909p:plain

このような関節 {P_0}, {P_1}, {P_2} + 末端 {P_3} で構成されているボーンツリーを考えます。{P_{target}} が末端の到達目標位置です。

f:id:hogetatu:20201129181121p:plain

1. 到達目標位置に末端 {P_3}' を置きます。
2. {P_2}{P_3} の距離 l_3 が変化しないと仮定し、{P_3}' から {P_2} に向かって l_3 だけ移動させた位置に {P_2}' を置きます。
3. 手順 2 を {P_0}' が決まるまで繰り返します。

f:id:hogetatu:20201129181205p:plain

4. 開始位置 {P_0}{P_0}'' を置きます。
5. {P_0}'' から {P_1}' に向かって l_1 だけ移動させた位置に {P_1}'' を置きます。
6. 手順 5 を {P_3}'' が決まるまで繰り返します。
7. {P_3}'' と到達目標位置を比較し、距離が閾値 (Precision) 以内であれば終了します。そうでない場合は手順 1 から繰り返します。

手順1~3を Backward Reaching 、手順4~6を Forward Reaching と呼びます。これらが FABRIK の基本的なアルゴリズムです。

Multi Effector FABRIK

youtu.be

プロパティ名 詳細
Root Bone ルートとするボーン
Effectors 末端設定リスト
制御する末端ボーンと追従する位置の組み合わせで設定
Precision 反復(イテレーション)を終了する末端 Item と Effector の距離閾値
Max Iterations 最大イテレーション回数
Propagate to Children 補正後に子ボーンにも変更を反映するか


FABRIK は複数の Effector に対応しています。まずはアルゴリズムについて簡単に解説しておきます。

f:id:hogetatu:20201129213159p:plain

このような関節 {P_0}, {P_1}, {P_2}, {P_4} + 末端 {P_3}, {P_5} で構成されているボーンツリーを考えます。{P_{t1}} が末端 {P_3}{P_{t2}} が末端 {P_5} の到達目標位置です。

f:id:hogetatu:20201129213518p:plain

まずは単一 Effector の時と同様に Backward Reaching していきます。{P_1} が合流ポイントですが、ここでは気にせず {P_1}'{P_1}'' を別途定義します。

f:id:hogetatu:20201129213831p:plain

次に Forward Reaching していきますが、{P_0}''' から ({P_1}' + {P_1}'') / 2 に向かって l_1 だけ移動させた位置を {P_1}''' とします。これによって複数の Effector を処理する中でバランスの良い位置に分岐点が移動していくようになります。後は同様に閾値以内に収まらなければ最初から繰り返します。

このノードでは Root Bone と複数の Effector + 到達目標位置を与えるだけで中間にある全てのボーンで FABRIK を計算するというシンプル設計になっていますが、それ故に細かい設定ができないので単純に使うと意図しない形状になるため注意が必要です。

f:id:hogetatu:20201123182049p:plain

例えばこのように両手に Effector を設定して引っ張り合う場合、本来は形状を維持するべき胸と両肩による逆三角形が崩れてしまいます。ボーンツリー上では両肩の間には依存関係が無いためです。

f:id:hogetatu:20201123205811p:plain

このように FABRIK で処理した後に戻すことで形状を維持するようにはできますが、やはり反復の中で考慮しなければ IK の結果としても中途半端になってしまうため用途は限られてきそうです。

CCD IK (Cyclic Coordinate Descent IK)

youtu.be

プロパティ名 詳細
Items 関節リスト
Effector Transform 末端の到達目標位置/回転
Precision 反復(イテレーション)を終了する末端 Item と Effector の距離閾値
Max Iterations 最大イテレーション回数
Start from Tail 終端から最適解を求めるか
Base Rotatin Limit Rotation Limits に指定されなかった Item の角度制限値
Rotatin Limits Item の角度制限値
Propagate to Children 補正後に子ボーンにも変更を反映するか


CCD IK は Cyclic Coordinate Descent IK の略称で、FABRIK が Backward Reaching によって決定した関節位置を基準にして関節角度を決定するのに対し、CCD IK は関節から末端に向かうベクトルが関節から到達目標に向かうベクトルに沿うように関節角度を決定するという手法です。

f:id:hogetatu:20201129220629p:plain

このような関節 {P_0}, {P_1}, {P_2} + 末端 {P_3} で構成されているボーンツリーを考えます。{P_t} が末端の到達目標位置です。

f:id:hogetatu:20201129220744p:plain

{P_2} から {P_3} に向かうベクトルが、{P_2} から到達目標位置に向かうベクトルに沿うように {P_2} を回転させます。

f:id:hogetatu:20201129221106p:plain

同様に {P_1} から {P_3}' に向かうベクトルが、{P_1} から到達目標位置に向かうベクトルに沿うように {P_1} を回転させます。これを繰り返し、閾値以内に収まらなければ最初から繰り返します。

また、検証して気付いたのですが ノードで指定する Rotation Limit は全体ではなく一回のイテレーションで考慮する変化量 になります。つまり角度制限を 1 度で指定していた場合、イテレーション回数を 10 回に指定していれば関節角度としては最大で 10 度まで変化するようになります。イテレーション回数を変化させると最終的な角度制限値まで変化してしまうので注意して下さい。更に距離や角度制限によって最終的に Effector が目標に到達できない場合、末端が伸びる形になってしまうのも使いにくい点となっています。

例えば Base Rotation Limit = 3, Max Iterations = 10 の時は到達できませんが、

f:id:hogetatu:20201123221326p:plain

Base Rotation Limit = 3, Max Iterations = 20 の時は到達できます。

f:id:hogetatu:20201123221439p:plain


Fullbody IK

youtu.be
youtu.be

プロパティ名 詳細
Root ルートとして扱う関節
Effectors 末端として扱う関節リスト
- Item 対象の Item
- Position 追従位置
- Position Alpha 位置ブレンド
- Rotation 追従角度
- Rotation Alpha 角度ブレンド
- Pull 1回のイテレーションで追従位置へ移動させる割合
一度に大きく追従させるとポーズが破綻しやすくなる
Constraints 拘束条件リスト
- Item 対象の Item
- Enabled 有効フラグ
- Use Stiffness Stiffness使用フラグ
- Linear Stiffness 移動値Stiffness(BoneTranslationの変化しにくさ)
※手元で挙動を確認できず。0を入れても固定されてしまう
- Angular Stiffness 回転値Stiffness(BoneRotationの変化しにくさ)
- Use Angular Limit 回転角制限使用フラグ
- Angular Limit  
- - Limit Type X/Y/Z 軸別の回転角制限タイプ
- - Limit 軸別の制限角 (Degree)
- Use Pole Vector Pole Vector 使用フラグ
- Pole Vector Option Pole Vector の種類(方向もしくは位置)
- Pole Vector 関節を回転させる時の基準方向/位置
- Offset Rotation 基準軸を構築する際の回転オフセット
デバッグ描画には反映されるが、実際に回転角制限を行うと
オフセット前の範囲でClampされている挙動をする
Solver Property  
- Default Target Clamp 1回のイテレーションで追従位置へ移動させる割合
一度に大きく追従させるとポーズが破綻しやすくなる
- Precision 反復(イテレーション)を終了する末端 Item と Effector の距離閾値
- Dumping ダンピング。高ければ補正時に振動しにくくなるが
収束しにくくなる事がある
- Max Iterations 最大イテレーション回数
- Use Jacobian Transpose On: Jacobian Transpose を使用
Off: Jacobian Psuedo Inverse Damped Least Square を使用
Motion Property  
- Force Effector Rotation Target 末端を設定した Rotation に合わせて回転させるか
- Only Apply when Reached to Target 追従位置に届く場合のみ末端を回転させるか
Propagate to Children 補正後に子ボーンにも変更を反映するか


Fullbody IK はヤコビ行列を使った一般的な手法ですが、「Use Jacobian Transpose」を切り替えることで Jacobian Transpose と Jacobian Psuedo Inverse Damped Least Square を切り替えられます。記事冒頭で「内部実装の理解は直感的な動作をしなかった時のため」と書きましたが、Fullbody IK は他の近似的な手法と比較すると複雑な計算が必要なだけあって副作用が少ないため、機能を利用するという意味ではアルゴリズムを理解する必要はあまり無いと言えます。計算コストは高いので、利用する場合はその点にだけ注意して下さい。

アルゴリズムの詳細な解説は Fullbody IK ノードの実装でリファレンスされている サーベイ論文 を参照してもらうのが良いと思いますが、ここでもアルゴリズム(というより Fullbody IK の考え方)についてだけ簡単に解説しておきます。

f:id:hogetatu:20201202013502p:plain

このような関節 {P_0}, {P_1}, {P_2} + 末端 {P_3} で構成されているボーンツリーを考えます。この構成では関節 {P_0}, {P_1}, {P_2} のどれが動いた時にも末端 {P_3} の位置は変化します。

f:id:hogetatu:20201202225820p:plain

関節 {P_1} が微小角度 {\Delta \theta_1} だけ回転した時、末端 {P_3} はそれに連動して微小距離 {\Delta P_1} だけ移動します。同様に関節 {P_2} が微小角度 {\Delta \theta_2} だけ回転した時、末端 {P_3} は微小距離 {\Delta P_2} だけ移動します。つまり回転行列として考えれば {\Delta P}=J{\Delta \theta} という式で表すことができ、この時の Jヤコビアン(ヤコビ行列)と言います。この場合に {\Delta P} から {\Delta \theta} を求めたいのですが、三次元空間において伸び縮みしない剛体を三つ以上の関節で IK させる場合は解が無数に存在してしまうため、擬似逆行列を用いてノルムを最小にするような解を求めます。これによって決定した {\Delta \theta} を用いて末端 {P_3} を更新し、距離が閾値以上であればイテレーションを繰り返すという手法です。

Fullbody IK の実装は参考となる資料については以前まとめたものがあるのでそちらを参照して下さい。(プラグインは習作なのでメンテされてません…!)

hogetatu.hatenablog.com


終わりに

ようやく腰を据えて Control Rig を触り始めましたが、感触としては非常に良いので期待感が強いです。今後の更新も追っていきたいと思います。

明日は kamitani_08 さんです。上司からの脅しに負けない良記事に期待です。