FinalIK for VRChat [多関節アーム追従]

# はじめに
VRChat(以下VRC)での使用を想定したFinalIKの設定方法についてまとめました．

今回は関節数がヒトの腕よりも多いような多関節アームを対象として，

- FABRIKを使ったアームのアバター追従
- Constraintやアニメーションと組み合わせたIK
- FABRIKとCCDIKの違い
  
について説明し，下図のようなアーム制御を試みます．
<img width="400" alt="filanik_fabrik_result.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/f38c8ad2-3f23-9739-b414-5af881b8cf93.gif" />

また，今回使用する多関節アームを[Booth](https://chootana.booth.pm/items/2801406)で公開します．（FinalIK設定済み）
興味ある方はダウンロードして触ってみてください．


## 概要
[前回の記事](https://qiita.com/Chootana/items/e9c05ebbaa52d76ac5dd)ではFinalIKの基本的な使い方として，アイテムのアバター追従やアイテム位置の切り替えについて説明しました．しかし↑のケースに限って言えば，UnityのConstraintを使うことでも再現可能です．

https://docs.unity3d.com/ja/2018.4/Manual/Constraints.html


IK制御が真価を発揮するのは，より複雑な骨格構造を持つモデルを制御する時です．
具体例として，下図のような多関節アームの制御について考えます．

<img width="400" alt="ArmOverview.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/b049143d-e000-33dd-47f7-fdba82e2188d.png" />

中間に分岐がなく一直線であるため構造は簡単ですが，関節数が8個あります（前回は3つ）．
IKを使わずにこのアームを制御するためには，例えば全ての関節にRotation Constraintを追加し，実際の動きを確認しながら，参照する関節やその影響度を何度も調整する必要があります．また全ての関節をConstraintで調整すると，末端の位置を自由に動かすことが困難です．（つまりConstraintによる制御はFK制御です．）

大半のケースでは，多関節アームの中間関節の姿勢よりも末端位置の方が重要になります．

そこで今回の記事では，
**「多関節アームの末端位置を自由に操作する」**
ために必要なFinalIKの設定方法について紹介します．



## 対象読者
- VRCでFinalIKを使いたい方
- Avatar3.0でアバターをアップロードしたことある方

FinalIKを初めて触る方は[前回の記事](https://qiita.com/Chootana/items/e9c05ebbaa52d76ac5dd)から試してみてください


## 環境
**注意**: VRCのバージョンによってVRC内でのFinalIKの挙動が変更される可能性があります．
動作確認した環境は以下の通りです．

- Unity: 2018.4.20f1 
- VRC: 2021.1.2
- [FinalIK](https://assetstore.unity.com/packages/tools/animatiON/final-ik-14290)
- [UTS2](https://unity-chan.com/download/releaseNote.php?id=UTS2_0): v2.0.7

# 全体図
<img width="800" alt="Overview.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/f990cb78-f783-84ce-1687-6465833f1915.png" />
全体の階層構造は以下の通りです．

- Avatar(VRC Avatar Descriptorがある階層)
    - Armature（HMDやコントローラで操作するスケルトン）
    - Body (スキニングされたモデル)
    - IKArm
      - IKTargets 
      - IKControllers 
      - Arm 

## 多関節アームを[Booth](https://chootana.booth.pm/items/2801406)からダウンロードした場合

- 先にFinalIKとUTS2をimportする
- その後，IKArm.unitypackageをimportする
- IKArm.prefabを用意したアバター直下に置く


## Point
- VRCのバージョン変更によってVRC Avatar DescriptorやArmatureの操作とFinalIKの挙動が衝突する可能性があります．
- そこでFinalIK由来のコンポーネントはArmatureなどには直接追加せず，独立に用意します．
- 最後にIKTargetsやArmなどをConstraintによってArmatureの動きと紐づけることで，上記の衝突を極力防ぎます．


# Arm と IKTargets
![ArmExplain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/c5e6b91e-1404-7fb1-da37-b9d421f2e14a.png)
![ArmExplainInspector.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/8621f39d-171d-4b16-8ba6-d3d0aac94ee8.png)


[前回の記事](https://qiita.com/Chootana/items/e9c05ebbaa52d76ac5dd)と同様な操作です．

- Armの位置を背中に配置する
- Parent ConstraintでArmature内のHipsに追従させる
- IKTargets内にTargetという名前の空オブジェクトを用意し，右足の位置に設定する
- Parent ConstraintでArmature内のfoot.Rに追従させる


# IKControllers 
Armを制御するためにIKコンポーネントを追加します．
多関節アームのためのIKソルバーとしてFABRIKを採用します．
FABRIKについてや，他のIKソルバー候補になるCCDIKについては補足で説明します．

![FABRIKExplain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/5f67083b-a226-39d5-f888-1993abd31868.png)

- Fix Transformsにチェックを入れる
- TargetにIKTargets/Targetを指定する
- Weightは1にする（IK制御の影響度）
- Bonesの下にある+ボタンを押して，Armの関節数と同じ数の項目を追加する
- Bonesの上の項目にArmの関節のRootにあたる親関節を追加する
- 階層順に関節を指定し，最後の項目に末端関節を指定する
- IKControllersの階層にIK Execution Orderを追加し，FABRIKを指定する
- FABRIKコンポーネント自体のチェックは外す

最後に指定した関節がTarget位置に一致するようにIKが解かれます．
Bones項目に全ての関節を指定せずとも動作しますが，末端関節は必ず指定します．


# 結果
![filanik_fabrik_result.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/f38c8ad2-3f23-9739-b414-5af881b8cf93.gif)

プロジェクトを実行して，Armが右足に追従すれば成功です！（分かりやすいようにArmを右足から少しずらしています）
右足に追従しているTargetの位置に一致するようにArmの先端が移動し，結果的に中間の関節の姿勢が求まる様子が分かります．
このように多くの関節を柔軟に操作できることがIK制御の利点の一つです．


## 多関節アーム先端の高さ固定（フルトラ向け）
フルトラッキング（フルトラ）をしている方に向けて，多関節アームの先端位置の高さを床に固定する小技を紹介します．
![TargetConstraint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/fd2922f8-1e88-c316-eeff-05ea0b2b0800.png)

- IKTargets/Targetで設定したParent Constraint内でConstraint Settingsの▶をクリックする．
- 表示された項目の中でFreeze Position Axes欄のYのチェックを外す

![filanik_fabrik_constraint2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/0e591af3-0826-af7b-ed0e-c3872fc3336e.gif)

プロジェクトを実行し右足を動かしてみると，Armが右足に追従しつつ床の高さを保っているのが分かります．またHipsを上下させてもアームの先端位置が変わらないように姿勢が変化します．（厳密にはキャリブした時のTargetの高さで固定されます）
このようにFinalIKだけでなくConstraintやAnimationを組み合わせることで更に柔軟な制御が可能になります．


# FABRIK VS. CCDIK
多関節アームの制御手法としてFinalIKにはFABRIKとCCDIKが用意されています．
両者の特徴や違いを簡単にまとめました．

## [CCD](https://t.co/NuWJNMUWNV?amp=1) 

- 90年代に提案された手法で，ゲームで使われるIKアルゴリズムの中で最もポピュラー
- 各関節がターゲットの方を向くように，末端から逆順に回転させていく
- 収束が早く，角度制限があっても高速
- 関節数が多い（IKチェーンが長い）と不利で，不自然な姿勢に収束することが多い
- 分岐構造に適用するのが難しい

![CCDOverview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/226e6ad3-ceda-9bbc-3f3a-69e4e1733200.png)
<https://mukai-lab.org/content/CcdParticleInverseKinematics.pdf>より引用

## [FABRIK](http://andreasaristidou.com/publications/papers/FABRIK.pdf)

- Forward計算とBackward計算のパートがあり，各ステップでBoneの位置が合うように修正する
- 収束後の姿勢が自然になりやすい
- 角度制限があるとCCDよりも収束が遅くなる
- 複数チェーンに対応可能（手や体全体の制御などにも有効）

![FABRIKOverview2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/19e02d2b-00ae-7c00-67cd-284c5387b4fe.png)
FABRIKの計算アルゴリズム
<http://andreasaristidou.com/publications/papers/FABRIK.pdf>より引用

## 多関節アームを用いたFABRIKとCCDIKの比較

多関節アームを制御する時のFABRIKとCCDIKの収束結果をUnity上で比較しました．
([Booth](https://chootana.booth.pm/items/2801406)からダウンロードした場合，FABRIK_CCDIKというSceneをダブルクリックした後，プロジェクト実行してください)

ターゲットを上下左右に動かすと，CCDIKの方は動作が不安定で不自然な姿勢のまま追従しています．
一方でFABRIKの方は動作が自然で，追従の仕方も直観的であることが分かります．
![FABRIK_CCDIK2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404071/39c5c334-b662-7cca-5f19-2d292e2ec0f4.gif)
どちらの手法が最適であるかは制御したいモデルによって変わりますが，多関節アームの場合はまずFABRIKを検討してみてください．


# 最後に
複数のIKアルゴリズムを実装して，それぞれ比較するのは大変な作業ですが，FinalIKとUnityを使うと簡単に検証することができます．更にIK制御結果をVR上で確認すると，IKの理解がより深まると思います．

VRC向けにFinalIKの設定を行ったら必ずアバターをアップロードしてVRC内で動作確認しましょう．