Bio IKで指にIKを付けてみた ＋ スマホVRで動かしてみた

以下の画像のような感じです（[Bio IKのストアページ](https://assetstore.unity.com/packages/tools/animation/bio-ik-67819?locale=ja-JP)より）。

![Bio IK](https://assetstorev1-prd-cdn.unity3d.com/package-screenshot/4f9ac79a-b479-4ab4-8aa3-66b90b0cdd3b.webp)

今後、ハンドトラッキングとか流行りそうだし、その際に便利そうかなと思ったので、記事にしてみました。

# そもそも何がしたいの？

以前、私は「スマホVRでハンドトラッキングをやってみた」的なUnityアセットを作成して、[こちらの記事](https://qiita.com/NON906/items/0d64635571d4a11490ca)を投稿しました。
その後、さらに機能を拡張して、[HandMR](https://github.com/NON906/HandMR)という形になりました。

そこでは、手をLineRendererなどで簡素に表示していましたが、それだけでは面白くないだろうと思い、3Dモデルを動かしてみようと思ったのですが、向きが取得できていないのもあり、あまり上手くいきませんでした。
それで、「指の座標だけでも簡単にモデルを動かせるようなものはないのか」と思い探してみたら、セールの抱き合わせで付いてきたこのアセットが使えそうだということになったので、試してみました。

ちなみに同じIKのアセットに[Final IK](https://assetstore.unity.com/packages/tools/animation/final-ik-14290?locale=ja-JP)というものがあり、そちらにもFinger Rigというもので設定できますが、向き（Rotation）が無いせいなのか、上手くいきませんでした。
ただFinalIKのVRIKという機能も使いたかったので、BioIKとFinalIKを併用することにします（後述）。
もし、FinalIKのみでかつ向き（Rotation）が分からなくても出来る方法があれば、コメントください。

# 設定方法

モデルにBioIKコンポーネントを付け、各パラメータをサンプルシーンを参考に設定すれば完了です。以上（手抜き）。
なお手の指先のように、空のゲームオブジェクトが追加で必要なことがありますが、サンプル通りにやれば問題ないと思います。

# スマホVRで使ってみた

以下のような感じです。
「Articulated Hand」を真似して設定しましたが、手首が上手くいっていないような感じなので、手首にもObjectiveの「Position」を追加しました（パラメータはデフォルト）。
なお、モデルは[Unityちゃん](https://unity-chan.com/)（© UTJ/UCL）を、ステージは[Magic Mirror Lite](https://assetstore.unity.com/packages/tools/particles-effects/magic-mirror-lite-reflection-for-unity-34824?locale=ja-JP)を使用しております。

![Screenshot_20210415-212741_HandMRModel.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427156/2f73b0ef-ca93-9aa0-88e3-fd4898494f88.jpeg)

# スクリプトからの設定方法

BioIKは自由度が高い反面、パラメータが非常に多く、毎回モデルごとに設定するのはとても手間がかかります。
そこでスクリプトを使って自動で設定してみます。
一部抜粋すると、以下のようなコードになります。

```Sample.cs
using BioIK;

// …（中略）

    var bioIK = animator.GetBoneTransform(HumanBodyBones.Hips).gameObject.AddComponent<BioIK.BioIK>(); // animatorは対象のモデルのAnimator
    bioIK.SetGenerations(2);
    bioIK.SetPopulationSize(75);
    bioIK.SetElites(2);
    bioIK.Smoothing = 0f;

    // 手首の場合
    var boneTrans = animator.GetBoneTransform(HumanBodyBones.LeftHand);
    var bioSegment = bioIK.FindSegment(boneTrans);
    var bioJoint = bioSegment.AddJoint();
    bioJoint.X.Enabled = true;
    bioJoint.X.Constrained = true;
    bioJoint.X.LowerLimit = -60f;
    bioJoint.X.UpperLimit = 60f;
    bioJoint.Y.Enabled = true;
    bioJoint.Y.Constrained = true;
    bioJoint.Y.LowerLimit = -60f;
    bioJoint.Y.UpperLimit = 60f;
    bioJoint.Z.Enabled = true;
    bioJoint.Z.Constrained = true;
    bioJoint.Z.LowerLimit = -60f;
    bioJoint.Z.UpperLimit = 60f;
    bioJoint.JointType = JointType.Rotational;
    bioJoint.SetOrientation(Vector3.zero);
    var bioPosition = bioSegment.AddObjective(ObjectiveType.Position) as Position;
    bioPosition.SetTargetTransform(target); // targetは対象のオブジェクトのTransform
```

上記のようなコードをStart()やエディタ拡張で実行するようにすれば、モデルごとに設定する手間が省けます。

# FinalIKとの併用について

前述の[Final IK](https://assetstore.unity.com/packages/tools/animation/final-ik-14290?locale=ja-JP)には、VRIKというコンポーネントがあります。
これは足のIKを設定して動かすことも出来ます（これだけならBioIKでも出来る）が、設定していない場合でも、他の部位（頭など）に応じて足の動きも自動で行われます。
これを使えば、全身を動かすことも可能ですが、そのままBioIKと併用しようとすると、お互いを上書きしようとするので、以下のようにする必要があります。

- Project SettingsのScript Execution Orderで、「RootMotion.～」よりも後ろに「BioIK.BioIK」を追加
- BioIKを使いたい箇所以外（手首～指先以外の部分）はJointやObjectiveを設定しない

なお前述の通り、指の向き（Rotation）が分かっているのであれば、FinalIKのFinger Rigで済むので、BioIKは不要です。

# 全身を動かしてみた

BioIKとFinalIK（VRIK）を併用して、全身を動かした結果がこちらです。

![full.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427156/a8ecef31-ae00-777e-636d-7e7e027d6780.gif)

スマホのカメラでハンドトラッキングしているため、手の認識範囲が限られたり、認識（特に左右の判別やグーにしたとき）が悪かったりしていますが、それでも全身の動かせるというのは魅力的です。

使用アセットが多く手間がかかるため、全体の内容はいまのところ非公開ですが、要望があれば公開するかもしれません。