UE4によるOculus Quest ハンドトラッキング 自前対応への道

#UE4+OculusQuest ハンドトラッキングを待ちきれない人へ

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">OculusリポジトリのUE4.24.1で、QuestのHand Tracking動いた！<br>マニフェストを書き加えて有効化し、C++からOVRPluginを直呼びすればOK。Pinchも拾えてテストは問題なさそう。<br><br>UE4対応は来年ってアナウンスあったけど、C++からは十分利用できる。中の人に感謝。<a href="https://twitter.com/hashtag/UE4Study?src=hash&amp;ref_src=twsrc%5Etfw">#UE4Study</a> <a href="https://twitter.com/hashtag/UE4?src=hash&amp;ref_src=twsrc%5Etfw">#UE4</a> <a href="https://twitter.com/hashtag/OculusQuest?src=hash&amp;ref_src=twsrc%5Etfw">#OculusQuest</a> <a href="https://t.co/6owdHFfgPx">pic.twitter.com/6owdHFfgPx</a></p>&mdash; はるべえ (@ruyo_h) <a href="https://twitter.com/ruyo_h/status/1209571931369852928?ref_src=twsrc%5Etfw">December 24, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#お断り
UE4でのOculusQuestハンドトラッキングの対応は「in the first half of 2020」とアナウンスされています。
この記事の実装は**数カ月後には役立たず**になります。
https://developer.oculus.com/blog/hand-tracking-sdk-for-oculus-quest-available/
また**Unity向けには既にインテグレートされたSDKが提供されています**。


**それでも… あなたは 本当に… UE4で試したいですか…？**

**良いでしょう… 私は止めません。前のめりに実装しましょう！**


#UE4によるOculus Quest ハンドトラッキング 自前対応への道
##準備＆覚悟

- SSD空き容量200GBくらい（HDDの場合は作業時間が数倍伸びます）
- 作業時間1~2日程度の余裕（それなりな個人PC＆慣れていれば半日程度で完了します）
- UE4およびVRへの熱意（長時間のビルド/シェーダコンパイル、意味不明なエラーに耐えられる心）

## 手順 概要
- Oculusのgithubからソースをcloneする
- ↑をビルドし、UE4エディタからc++のプロジェクトを作成する
- Engine側、プロジェクト側のソースを書き換え、ハンドトラッキングを有効にする
- 再度UE4エディタに戻り設定、Blueprintを組んでQuestに転送する

## 手順 具体的に

### Oculusのgithubからソースをcloneする

githubアカウントを、EpicGamesアカウントに紐付けする。
https://www.unrealengine.com/ja/ue4-on-github

以下をcloneする。(404ページが出る場合は、上記の紐付けを確認ください)
https://github.com/Oculus-VR/UnrealEngine/tree/4.24

### ビルドする

cloneしたパスより、以下の手順で操作する。
※UnityのMobile作業環境と競合することがあるらしいのでご注意ください。（自分は該当しないので伝聞です）

- `UnrealEngine/Setup.bat` を実行する
- `UnrealEngine/Engine/Extras/AndroidWorks/Win64/CodeWorksforAndroid-1R7u1-windows.exe`をインストールする。設定はデフォルトでOK
- `UnrealEngine/GenerateProjectFiles.bat` を実行する。`UnrealEngine/UE4.sln` が生成される。
- 上記slnをVisualStudio（私はVS2017を利用）で開いて、そのまま`F5`キーを押してビルドを開始する。そのまま数時間放置。

ビルドに数時間、その後シェーダコンパイルに数十分、そしてエディタ起動画面が表示される。


|タイトルバーが青いエディタが起動すればOK！|
|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36233/49c0d063-2f29-32df-fe66-d85290343ed4.png)|||

そのエディタで任意のプロジェクトを作成（ここではVirtualRealityを選択）する。
起動後にC++クラスを追加して任意の名前（ここではMyActor）を付けて保存。ビルドが完了するのを待つ

|C++プロジェクト設定を追加|
|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36233/2100b8a9-9a58-3a9e-2188-440711798664.png)|

### ソースを書き換え、ハンドトラッキングを有効にする

日本語のコメント部分は削除してください。。

エンジン側
マニフェストファイルの変更は プロジェクト側でも必要です。後述します。
また、謝辞に貼ったリンク先にも解説があるので 気になる方はそちらも参照ください。

```UnrealEngine/Engine/Plugins/Runtime/Oculus/OculusVR/Source/OculusHMD/OculusMobile_APL.xml

<if condition="bOculus6Dof">
  <true>
    <addFeature android:name="android.hardware.vr.headtracking" android:version="1" android:required="$B(bNotOculus3Dof)" />
>> ここを追加    <addFeature android:name="oculus.software.handtracking" android:required="false" />
  </true>
</if>
```

プロジェクト側ビルド設定（プロジェクト名はoc_handとしています）
OVRPluginの関数を直接呼び出せるようにします。

```UnrealProjects/oc_hand/Source/oc_hand/oc_hand.Build.cs
PublicDependencyModuleNames.AddRange(new string[] {
	"Core", "CoreUObject", "Engine", "InputCore",
>>これ	"OVRPlugin",
>>これ	"OculusHMD",
});
```

プロジェクト側ハンドトラッキング呼び出し（MyActorに実装）
大変シンプルなので、ヘッダを眺めればだいたい使い方が予想できます。

```MyActor.cpp
#include "OVR_Plugin.h"

void AMyActor::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);

  // ハンドトラッキングが有効か調べる
  {
    ovrpBool handTrackingEnabled = false;
    auto res = ovrp_GetHandTrackingEnabled(&handTrackingEnabled);
  }

  // 左手のスケルトン情報を得る
  // おそらくこれは固定値。後述の回転角度を適用して初めて手指のトラッキング結果となる。
  ovrpSkeleton skeleton;
  ovrp_GetSkeleton(ovrpSkeletonType_HandLeft, &skeleton);

  // 左手のトラッキング情報を得る
  ovrpHandState handState;
  auto res = ovrp_GetHandState(ovrpStep_Render, ovrpHand_Left, &handState);

  // handState.RootPose にてSkeletonの原点（手首付近）の姿勢が取得できる
  // handState.BoneRotations[boneID] にて手指の各関節の回転角度が取得できる
  // これらをskeletonに沿って姿勢適用すればOK

  // 座標系の変換には、
  // OculusHMD::ToFQuat や OculusHMD::ToFVector を利用できる
  // 最後にBlueprint側でskeletonをx100スケールすればUE4の座標と一致する
```

```c++

  // 追記ぶん skeleton計算
  ovrpHandState handState;
  auto res = ovrp_GetHandState(ovrpStep_Render, ovrpHand_Left, &handState);

  TArray<FTransform> leftTrans;
  ovrpSkeleton skeleton;
  if (ovrp_GetSkeleton(ovrpSkeletonType_HandLeft, &skeleton) == 0) {
    leftTrans.SetNum(skeleton.NumBones);
    for (uint32_t i = 0; i < skeleton.NumBones; ++i) {
      int boneID = skeleton.Bones[i].BoneId;

      auto aa = OculusHMD::ToFQuat(handState.BoneRotations[boneID]);
      auto q = aa;
      auto p = OculusHMD::ToFVector(skeleton.Bones[i].Pose.Position);

      auto t = FTransform(q, p);
      int tmp = skeleton.Bones[i].ParentBoneIndex;
      if (tmp >= 0) {
        t = t * leftTrans[tmp];
      } else {
        auto qq = OculusHMD::ToFQuat(handState.RootPose.Orientation);
        auto pp = OculusHMD::ToFVector(handState.RootPose.Position);

        t = t * FTransform(qq, pp);
      }

      leftTrans[i] = t;
    }
  }
```


### UE4エディタから設定、Blueprintを組んでQuestに転送する

一般的なOculusQuest用の設定をする。以下のリンク参照。
https://developer.oculus.com/documentation/quest/latest/concepts/unreal-quick-start-guide-quest/

上記に加えて、マニフェストファイルに`oculus.permission.handtracking` を追加する。

|マニフェストファイルに追記|
|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36233/31a631b1-e794-7e32-985c-fb6ae5fece53.png)|

MyActorをBlueprintで継承したMyActorBPを作成、デバッグにprintfやメッシュ配置用のノードを組んでレベルへ配置

|配置します|
|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36233/170b3b3a-f39f-9d15-0de7-0073e88a4734.png)|

|転送します|
|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36233/23c70073-1348-e771-583c-1f0fa10a815c.png)|


完了です。

# まとめ
OculusのリポジトリにあるUE4ソースに追記することで、一足早くハンドトラッキングを実装できました。
UnrealC++に慣れている方であれば簡単かもしれません。ややこしいのは指の姿勢反映あたりでしょうか。

解説はスキップしましたが、Pinch操作（親指と他の指をくっつける操作）や、現在のトラッキング精度パラメータなども取得できます。
是非ドキュメントを読んだり、ヘッダを眺めて利用してみましょう！

今後のハンドトラッキングの公式対応には、以下のような工程があると思われます。
少なくとも数ヶ月の間はOculusリポジトリを利用することになるでしょう。

|ハンドトラッキング公式対応までの工程（予想）|補足|対応状況（気がついたら追記）|
|:----|:----|:--|
|OculusリポジトリでSDKが更新される|自前実装が必要|**2019/12/26：UE4.24.1** <br>**2020/02/11：UE4.24.2。PCからハンドトラッキング利用できるようになった**|
|OculusリポジトリでハンドトラッキングがBlueprintに対応|自前実装は不要||
|EpicリポジトリのVRブランチにマージ|開発ブランチのため不安定||
|リリースブランチにマージ|previewとしてリリース|UE4.25やUE4.26に合わせるならpreviewへ。UE4.25.1などで対応する場合はそのまま本番へ|
|リリース|本番リリース||



# 勝手に謝辞
Unityでハンドトラッキングをしている人達が羨ましく悶々としていたところ、
こちらのマニフェストの記述を見てUE4側の対応を思い立ちました。ありがとうございました。上手く動作しました。
https://qiita.com/shiena/items/0b7735a80e7d4358e5fb#%E3%83%8F%E3%83%B3%E3%83%89%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E8%A8%AD%E5%AE%9A