【Final IK】3Dキャラクターを一人称視点で動かす

Oculus Quest 2のトラッキングで3Dモデルを自由に動かす方法、Camera位置をオフセットして快適な１人称視点にする方法を解説します。

### 環境
macOS Monterey 12.3.1
Unity 2021.3.2f1
Oculus Integration 39.0
Final IK 2.1
Oculus Quest 2

# 準備
## インポートしておくもの
- [Oculus Integration](https://assetstore.unity.com/packages/tools/integration/oculus-integration-82022?locale=ja-JP)
アセットストアにて無料で公開されています。

- [Final IK](https://assetstore.unity.com/packages/tools/animation/final-ik-14290?locale=ja-JP)
有料アセットですが、セールのタイミングで購入するとお得に入手できます。

- 3D人物モデル
お好きなものをご用意ください。今回は[BOOTH](https://booth.pm/ja)で販売されている「[QuQuさんちのネコちゃん](https://booth.pm/ja/items/1661885)」と「[エトワーニュ](https://booth.pm/ja/items/1585088)」を使用させて頂いています。


## 3DモデルとOVRPlayerControllerを配置する

ヒエラルキービューへドラッグ＆ドロップし、シーン上に配置します。
![イメージ (2)-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/7d831b36-1d37-cab1-4f6a-2fb043688308.jpeg)
OVRPlayerController > OVRCameraRig > **CentreEyeAnchor**にあるCameraコンポーネントが、HMD用のカメラとして使用されます。
元々あった**Main Cemera**は不要なので削除しておきましょう。

# Final IKで3点トラッキング

## トラッキング用に空のオブジェクトを作る
OVRPlayerControllerの中にある **CentreEyeAnchor**, **LeftHandAnchor**, **RightHandAnchor** それぞれの中に空のオブジェクトを作成します。オブジェクトの名前は HeadTarget, LeftHandTarget, RightHandTargetとしました。
![スクリーンショット 2022-05-15 午後2.54.35.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/e208f6eb-6bea-dfaa-9a87-5637944e7ad7.png)



## 3DモデルにVR IKをアタッチし、トラッキングターゲット3点を設定
3DモデルにVR IKをAdd Componentした後、**Head Target**と左右の**Hand Target**に先程作った空のオブジェクトをアタッチします。これだけで3DモデルをOculusの動きに対応させることができます。
![イメージ (6)-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/35b04648-d46c-76a3-ebd8-bce3a78302ee.jpeg)




# カメラの調整
## モデルの大きさをプレイヤーに合わせる
TransformのScaleで、3Dモデルの大きさを調整します。腕の長さを基準にすると良い操作感になりやすいです。
人の腕の長さは身長と大体同じなので、自分の身長と同じ大きさのCubeを用意して2Dモードで前後に並べると調整しやすくなります。
![スクリーンショット 2022-05-16 午後9.40.48.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/7c6ecbf4-aeb6-08db-ee01-a427ce6b20c3.png)
腕が短めのモデルだったので、腕の長さを寄せつつ身長とのバランスを取りました。
後に実機で確認しながら再調整したい項目です。


## Oculus Quest 2 におけるカメラ座標
OVRPlayerController > OVRCameraRig に入っているOVR Managerコンポーネントの**Tracking Origin Type**を、`Floor Level`に設定します。選択項目3つを軽く解説すると下記のようになります。

- `Eye Level`
ユーザーの身長に関わらず、指定した高さにカメラが設置されます。空から見下ろす場合などに選択します。

- `Floor Level`
足元を原点としたカメラ座標になります。
身長が180cmの人では地上から180cmの高さに、身長が130cmの人では地上から130cmの高さにカメラが設置されます。地面に立っている場合などに選択します。

- `Stage`
FloorLevelと同様に足元を原点としてカメラが設置されます。また、ユーザーによるセンタリングが反映されないという特徴があります。
決まった方向が前とみなされるので、現実のプレイエリアとリンクさせたアプリ開発などに使用できます。


## モデルの頭がカメラに映らないように設定
現在の状態で実行するとモデルの頭の内側が描画されてしまうので、対策が必要となります。
モデルの頭と体が別のオブジェクトになっている場合は、レイヤーで頭を指定してカメラから非表示にする方法が確実です。`Culling Mask`の項目からカメラに描画されるレイヤーを選択出来ます。

1. 頭のオブジェクトのインスペクターで、Layer > Add Layer… をクリック
2. 新規に専用のレイヤーを作成
3. 頭のオブジェクトに戻り、先程作成した専用のレイヤーをアタッチ
3. OVRPlayerController > OVRCameraRig > CenterEyeAnchorにあるCameraコンポーネントの`Culling Mask`のチェックボックスを開き、頭のオブジェクトにアタッチしたレイヤーのチェックを外す


![IMG_0233.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/c619442a-b08a-6aba-0bb2-6f292a98ecb1.jpeg)





頭が別になっていないモデルの場合は、次の**レンダリング範囲の設定**で改善できます。
エトワーニュのように頭の大きいモデルの場合はCulling Mask必須となりますが、頭の小さいモデルの場合は次の設定だけでも問題ありません。


## レンダリングの範囲を設定
OVRPlayerController > OVRCameraRig > CenterEyeAnchorにあるCameraコンポーネントの**Clipping Planes > Near**を設定します。
「カメラから何m以内は描画しない」という意味の設定項目です。
モデルの体型や頭の大きさにより最適値が異なりますが、仮に0.2とします。
後に実機で確認しながら調整したい項目です。

## 現在の視点と目標とする視点


現在のカメラ座標は画像のように首の真上になっている為、下を見ると体の断面が覗く状態です。
カメラを本来の目の位置に合わせてオフセットする必要があります。

![イメージ-1 3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/bbc0de85-42ca-adc2-0037-cdf7cae5ba32.jpeg)

![イメージ (1)-1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/6c1b6ce2-ef8d-b21c-adb5-6b5018529a74.jpeg)

ただし細身のモデルの場合は調整がほとんど不要な場合もあります。
モデルの体型により最適値が異なるので、こちらも確認しながらの調整が必要な項目です。


## カメラ座標のオフセット
CenterEyeAnchorの中に作った空のオブジェクト**HeadTarget**のTransformから、Positionを調整します。

![イメージ-1 2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/de2d25b0-47fc-e907-4f3e-66055cfde6a0.jpeg)


![イメージ (1)-1 2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/8bf541a7-4fd0-2250-7647-d1d74dc55137.jpeg)

画像のように、現在の視点と目標とする視点の差分を反転させた座標にオフセットします。
後ろにモデルが引っ張られることで、相対的にカメラが前に出たような位置関係を作ることができます。



![スクリーンショット 2022-05-16 午後3.36.47.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/e53e25ac-2fe5-da65-6c35-45220f055639.png)

↑こちらのモデルは細身なので、小さめの値で十分でした。

![スクリーンショット 2022-05-16 午後3.39.19.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/aca66b88-728f-7686-0eb1-a516616bb2b4.png)


↑こちらのモデルは体の厚みがある為、大きめの値にします。



![IMG_9128.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666148/0485742e-6f22-5513-951f-b38f80646e89.jpeg)

<br>
以上で、Oculus Quest 2で操作できる一人称視点の実装ができました。
理想的な視点になりましたが、こちらのモデルは手の角度が捩れてしまっているので続けて調整が必要です。


<br>
<br> <br>

### 参考にさせて頂きました
モデルの体の捩れを調整する内容を含む、Final IKの解説記事です

https://materializer.co/lab/blog/56

こちらの記事で、ものを掴む機能の実装ができます

https://hamachitaro.hatenablog.jp/entry/2019/11/11/110942

地形に合わせて足を設置させる方法が解説されています

https://www.hanachiru-blog.com/entry/2022/03/10/120000



<br><br>

下記記事も大変参考にさせて頂きました
https://qiita.com/pira/items/7121764bba7fc605426f
https://shinrinmusic.com/final-ik/
https://light11.hatenadiary.com/entry/2019/11/05/220200