なんかいろいろしてみます

Nov 14, 2017 - 2 minute read - HoloLens

HoloLensとImmersive,Editorのデバイス切り分けについて

UnityでHoloLens開発する際に行う実行環境による切り分け方法について書いてます.

*ここではMRデバイス,Windows MR ヘッドマウントディスプレイなどのことをImmersiveデバイスとして統一しています.

デバイス切り分けとは

Unityでは異なるデバイス(Windows,Mac,Androidなど)に対して同一のコードから実行ファイルを作成することができます. HoloLensではUnityが出力したプロジェクトデータを再度VisualStudioでビルドすることで実行ファイルを作成することができます. しかしUnityが提供する関数がすべてのデバイスで動作するわけではありません. 一部デバイスの固有な機能についてはUnityが関数が提供していても他のデバイスでは動作しません. またUnityのバージョンによっても利用できる関数や関数名が変更になる場合があります.

HoloLensの事情

HoloLensには固有の機能が複数搭載されており実行環境の条件も限られています. 固有の機能としては以下があります.

  • Spatialmapping : 現実空間の形状を利用できる
  • WorldAnchor : 現実空間にオブジェクトを固定できる

また実行環境の条件はUniversal Windows Platform(UWP)のx86である必要があります. UWPはUWP動作デバイス間でのコードの差異を抑え,セキュリティを向上させることができます. またC#で記述できるのでUnity上でも言語の違いを意識する必要はあまりないです. ただしUnityでの開発では一部Unityの提供する関数が動作しない場合があります. 特にアプリ全体のコントロール(終了など)やファイルI/O,通信系の関数はUWP専用として記述する必要があります.

例としては

  • UWPはTask,EditorではThread(Unity5.x系まで)
    • UWPのC#のバージョンでは非同期処理のTaskが利用出ますが,UnityのバージョンによってはTaskが利用できずThreadしか利用できない場合があります.
  • UWPはStreamWriter,EditorではUdpClient
    • UDP通信を行う場合Unityが利用できるC#の通信の関数とUWPのC#の関数が異なります.
 1 2 3 4 5 6 7 8 9101112131415161718192021222324
#if UNITY_UWP
        private StreamWriter writer=null;
#elif UNITY_EDITOR || UNITY_STANDALONE
        private Thread thread;
        private UdpClient udpclient;
#endif

        public void SendMessage(string data)
        {
#if UNITY_UWP
            if (writer != null) Task.Run(async () =>
            {
                await writer.WriteAsync(data);
                await writer.FlushAsync();
            });
#elif UNITY_EDITOR || UNITY_STANDALONE
            thread = new Thread(() =>
            {
                byte[] bytes = Encoding.UTF8.GetBytes(data);
                udpclient.Send(bytes, bytes.Length);
            });
            thread.Start();
#endif
        }

Immersiveデバイスの事情

HoloLensと同様にImmersiveデバイスもUWPで動作します(x64も可能). そのためHoloLensと同様にUnityで利用できる関数に対して制限があります. またImmersiveデバイスはHoloLensでは利用できない機能,Immersiveでは利用できない機能があります.

  • Boundary : VR空間に移動可能な範囲を定義できる

そのためHoloLensと同じUWPで動作しますがHoloLensとの機能の切り分けを行う必要があります.

Unity2017.1までは正式にImmersiveデバイスに対応していないため切り分けの関数はありません

UnityEditorの事情

  • Unity2017.1まで

UnityEditorではUWP特有の関数利用はできませんが,Unityが提供するHoloLensやImmersive特有の関数は利用することができます. そのためHoloLens用とデスクトップ用のアプリの開発を行う場合,UnityEditor上ではHoloLens用の関数とデスクトップ用の両方が動作できてしまいます. またUnityEditorのみ他のデバイスと異なる動作をさせる場合には他のデバイスの影響が出ないように切り分けを行う必要があります.

  • Unity2017.2から

BuildSettingのTarget Platformを「PC,Mac&Linux Standalone」にした場合は今までのEditor上での実行ができます. TargetPlatformを「UWP」に変更しMixedRealityポータルが有効な場合,Editor実行時にMixedRealityポータルが起動します. これによってImmersiveデバイスのUnityでのデバックが手軽に行えるようになりました.

Unityの実行環境への対策

HoloLens,Immersiveデバイスとそれ以外の切り分け方法

上記のようにUWPで動作しているデバイスに関してはUnityが提供しているdefine定義によって切り分けを行うことができます.

  • UNITY_UWP
  • UNITY_WSA

が利用できます. またUWP系とUnityEditorやデスクトップパソコン用に関数を切り替える場合には

  • UNITY_EDITOR
  • UNITY_STANDALONE

を利用して切り分けを行います.

例として,UnityではApplication.Quit();を呼び出すことでアプリを終了させることができます. しかしUWPではUWP上で動作しているUnityが終了しているだけで対象のUWPアプリ自体は終了しません. そのため追加で以下のようにUWP用に記述します.

1234567
  public void Exit()
  {
      Application.Quit();
#if UNITY_UWP
      Windows.ApplicationModel.Core.CoreApplication.Exit();
#endif
  }

このときUNITY_UWP内の関数はUnityEditor上では動作確認することができません. UWP用にUnityからプロジェクトを作成してVisualStudioでデバックを行うことで動作を確認できます.

HoloLensとImmersiveデバイスの切り分け方法

Immersiveデバイスが正式に対応したUnity2017.2からはHoloLensとImmersiveデバイスを確認できる関数が提供されています. using UnityEngine.XR.WSA;にあるHolographicSettingsを利用します.

例としてHoloLensでは利用しないskyboxをImmersiveの場合には有効にさせます.

1234
void Start () {
    if(HolographicSettings.IsDisplayOpaque) Camera.main.clearFlags = CameraClearFlags.Skybox;
    else Camera.main.clearFlags = CameraClearFlags.SolidColor;
}

Unityのバージョンによる切り分け方法

Unity2017.2ではImmersiveデバイスが正式に対応したことでnamespaceと関数が一部変更になっています. そのためUnityのバージョンを5.6系,2017.1系,2017.2系で移動して実行する場合関数の自動変換のエラーが発生する場合があります. Unityのバージョンによって利用するnamespace,関数を切り替える場合にはdefine定義によって設定が行えます.

  • UNITY_2017_2_OR_NEWER : Unity2017.2以上の場合有効
  • UNITY_2017_1_OR_NEWER : Unity2017.1以上の場合有効

これを利用することで

123456789
#if UNITY_EDITOR || UNITY_UWP
#if !UNITY_2017_2_OR_NEWER
using UnityEngine.VR.WSA;
using UnityEngine.VR.WSA.Persistence;
#else
using UnityEngine.XR.WSA;
using UnityEngine.XR.WSA.Persistence;
#endif
#endif

まとめ

  • 必要がなければUnityのバージョンを固定して,利用デバイスごとにプロジェクトを作った方がいいかも.
  • UnityのバージョンとUWPの切り分けを考慮するとUNITY_2017_2_OR_NEWERとUNITY_2017_1_OR_NEWERとUNITY_UWPとUNITY_EDITORとUNITY_STANDALONE入り乱れることになる.
    • HoloLensとImmersiveの切り分けを入れるとすごい
    • さらにAndroidとか入るとさらにすごい
  • Unity2017.2からHoloLensとImmersiveとデスクトップを同一プロジェクトで作成する場合,毎回BuildSettingからTargetPlatformを変更する必要が出てきた.