MagicLeapようのプロジェクトをUnityEditorで動かす

# MagicLeapようのプロジェクトをUnityEditorで動かす

この記事は、[Magic Leap Advent Calendar 2020](https://qiita.com/advent-calendar/2020/magicleap)の8日目です

### 動作環境
Unity 2019.3.13f1
MagicLeapSDK 0.24.0.20200310r

# はじめに
初めまして。やまだと申します。お仕事で２案件ほどMagicLeap開発に携わり、その中でUnityEditorでのコンテンツ確認などのデバッグ用のモードの担当を行いました
今回はその時のTipsの話をします

MagicLeapのプロジェクトを作っていると、ちょっとした変更などは実機ではなく、UnityEditorで確認したい。と言うことが多々あると思います
しかし、`MLHandTrackingBehaviour`などを使っていると、UnityEditorで実行してもエラーが出て動作の確認ができません。

Zero Iterationを使えばシミューレーションできますが、PC上では動作が重たくなったりするので、
「単純なエラーチェック」であるような、精度の高さが必要でないような環境では必要とまではなりません
（設定もエンジニア以外にはまだ難しい部分もあるかと思います）

なので今回は簡単に`MLHandTrackingBehaviour`などが入っていてもUnityEditorで実行する方法を紹介いたします

# やること
まずは普通に実行してエラーが出る箇所を確認します
![スクリーンショット 2020-12-07 12.28.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/456ab318-af36-7763-5e30-4532c6099868.png)

例えば画像の一番上のコードを見てみると、以下のように書かれています

```
public static MLResult Start(bool initializeValues = false)
        {
            #if PLATFORM_LUMIN

            MLResult _result = MLHandTracking.Start();
            if (!_result.IsOk)
            {
                Debug.LogErrorFormat("Error: MLHandTrackingStarterKit failed starting MLHandTracking. Reason: {0}", _result);
            }
...
}
```
エラーが出ていることからも分かるとおり、UnityEditorではHand系の処理がエラーで全く動きません

なので、ここの`#if PLATFORM_LUMIN`を以下のように書き換えます

```
public static MLResult Start(bool initializeValues = false)
        {
            #if PLATFORM_LUMIN && !UNITY_EDITOR

            MLResult _result = MLHandTracking.Start();
            if (!_result.IsOk)
            {
                Debug.LogErrorFormat("Error: MLHandTrackingStarterKit failed starting MLHandTracking. Reason: {0}", _result);
            }
...
}
```

`&& !UNITY_EDITOR`を入れることで、UnityEditorでのHand系の処理に入らないようにできます

他のところも同じようにすればエラーは出なくなるのですが、`MLAPISingleton`や`MLHandMeshing`を使っている場合は少しだけ工夫が必要です

結論から書いてしまうと、以下のようにする必要があります

```
public static MLResult RequestHandMesh(RequestHandMeshCallback callback)
        {
            #if !UNITY_EDITOR
            if (callback == null)
            {
                MLPluginLog.ErrorFormat("MLHandMeshing.RequestHandMesh failed. Reason: Passed input callback is null");
                return MLResult.Create(MLResult.Code.InvalidParam);
            }

            ulong requestHandle = MagicLeapNativeBindings.InvalidHandle;
            MLResult.Code resultCode = NativeBindings.MLHandMeshingRequestMesh(Instance.nativeTracker, ref requestHandle);
            if (resultCode != MLResult.Code.Ok)
            {
                MLPluginLog.ErrorFormat("MLHandMeshing.RequestHandMesh failed to request hand mesh. Reason: {0}", resultCode);
                return MLResult.Create(resultCode);
            }

            Instance.pendingQueries.Add(new Query(requestHandle, callback));

            return MLResult.Create(resultCode);
#else
            return MLResult.Create(MLResult.Code.Ok);
            #endif
        }
```
ここでは通常の処理を`#if !UNITY_EDITOR`で括って、`else`として`return MLResult.Create(MLResult.Code.Ok);`
を入れています。単純に処理が正常に終了した。と判断させているだけですね

このように、UnityEditorのための処理を書いていけばEditorで動かすことが可能になります

### カメラの設定
Editorで動かせる様になって、確認していると、カメラの画角がMagicLeapでみるのと少しずれていることに気づくと思います。
MagicLeapは実行時にカメラのFieldOfViewをいじっているのですが、Editorではその処理が走らないためです。
ここはカメラにのFieldOfViewに`44.57381`の値を設定するとある程度同じ様に見えます

### やっておくと良いこと
MagicLeapはMR機器なので、UnityEditorでシミュレートするには無理があります
ただ最初に書いた通り、簡単な確認はEditorでしたいです
なので、UnityEditorでデバッグできるようにしておくと便利です
弊プロジェクトでは以下の機能を入れていました
・カメラの移動
・コンテンツの倍速機能
・タッチ処理をクリックで行えるように

# 最後に
今回の変更は簡単に行えますが、１点注意があります
それはMagicLeapSDKに手を加えているため、`もしアップデートがあった場合は同じ変更を加える必要がある`
と言う点です。しかしEditorで確認できるようになれば、実機がなくてもコンテンツの作成・確認が容易になるので、
これらの変更とデバッグモードを作るのをお勧めします。