HoloLensのアプリ開発の準備とはまったこと

「[【大阪】はじめてのHoloLensハッカソン](https://osaka-driven-dev.connpass.com/event/50497/)」に参加してきた。
HoloLensでアプリ開発は初めてだったので、予め準備したことと、ハッカソン中にはまったことなどを書いていこうと思う。
結果としては、目標の半分が出来て、半分出来なかった感じ。
ただ、HoloLensのアプリ開発で出来上がったものはイメージしてたものに近く、比較的簡単に実装できた。

# 今回作るもの
これ。2分35秒あたりまで。
https://youtu.be/tgfEWZUocfQ?t=2m28s

# 準備したこと
## 環境構築
Windows10 x64 ProにUnity、VisualStudio、HoloLensエミュレータを入れる。
バージョンがちょっと前のだが、ビルドまでの手順がまとめられてYouTubeにあがっている。基本的にこの通り。
https://www.youtube.com/watch?v=81N9cU47tn8

公式ドキュメントとしては以下。こっちもバージョンが少し古い。
https://developer.microsoft.com/en-us/windows/holographic/install_the_tools

必要なものは以下になる。バージョンはこれ以降のものになる。

* Visual Studio 2015 Update 3
* ツール(1.4)とWindows 10 SDK (10.0.10586)
* Unity 5.5.0f3
* HoloLens Emulator (build 10.0.14393.0)

今回、僕が使ったのは、ツール(1.4)とWindows 10 SDKはその時の最新を、Unityは5.5.1f1を、HoloLens Emulatorはbuild 10.0.14393.0を使用した。

### Visual Studio 2015
Visual Studio 2015をインストールしていなければ、インストーラでインストールする。
もし、Visual Studio 2015はインストールしているが、Visual Studio 2015にUpdateが適用されているか、ツール(1.4)とWindows 10 SDKが入っているかどうかを確認するのは、Visual Studio 2015を起動し、以下からダイアログを開く。

`メニュー > ヘルプ > Microsoft Visual Studio のバージョン情報`
![001.png](https://qiita-image-store.s3.amazonaws.com/0/141310/ae67771f-f24f-91e1-2814-90ef153f5856.png)

ダイアログの上部にUpdateバージョンがあり、インストールされている製品の一覧に「ユニバーサルWindowsアプリ用Visual Studio Tools」があるか確認する。
![003.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/5b0290fa-d677-da49-bbfb-8da041a69935.png)

Update 3でないか、ツールがなければ、Visual Studio 2015のインストーラを取得し、個別インストールをする。
不足分や最新との差分のみインストールすればいい。

個別インストールは、インストーラを起動し、カスタムを選択する。
![004.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/d2bd53ee-682d-2087-d583-902b6ba5db3b.png)

必要なものにチェックを入れて、インストールをする。
![005.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/5c440210-24f6-ef26-7d2f-7c2e3b0ef611.png)

### Unity
Unityをインストールしていなければ、インストーラでインストールする。
もし、Unityをインストールしていて、バージョンが違うか、またはWindows Storeのコンポーネントを一緒にインストールする必要があるので、Windows Storeのコンポーネントがインストールされていなければ、追加でインストールする。

バージョンを上げる場合はUnityのチェックボックスと、Windows Storeのコンポーネントのチェックボックスにチェックを入れる必要がある。
![007.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/ad50d883-aba8-9f6d-e6e7-580360333d36.png)

Windows Storeのコンポーネントのみなら、Windows Storeのコンポーネントだけチェックを入れてインストールする。
![006.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/d513be2f-1149-9723-2f19-7a59ed773737.png)

## チュートリアル
今回のアプリの機能もそうだが、基本的には一度チュートリアルをしておくと、HoloLensで何ができるのかが分かる。
チュートリアルは以下。
https://developer.microsoft.com/en-us/windows/holographic/holograms_101#chapter_1_-_.22holo.22_world

僕も事前にチュートリアルは一部を実際にやっており、だいたいどんなことができるか確認していた。
HoloLensエミュレータがどこまでできるのか分からなかったのと、音声認識とかはHoloLens本体がなければおそらくできないと思うので、そういうのは目を通しただけでやっていない。

なお、HoloLensエミュレータでの操作は、WindowsキーでBloom、右クリックでAir tap、ドラッグで向きを変えられるようになっている。

# アプリ実装
今回のアプリは、変身のゲームセレクトシーンを作りたいので、カードが宙をクルクルと回って、Air tapで選択できるようにするというもの。
順番に説明していく。

## マルチシーン対応
Unityで複数人が同時に同じシーンファイルを編集するとマージするのが大変だったりするので、今回はマルチシーンを使うことにした。
実は初めてマルチシーンを使った。

まずはカメラ、ライトと、HoloLensアプリのベースになる設定をしたシーンをメインシーンとして作成した。
実装者はカード部担当と、Air tapシステム担当に分けたので、マルチシーンもそれぞれに分けるようにした。
カード部をGameSelect、Air tapシステムをPlayerという名前にした。
こんな感じになる。
![008.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/a80c2215-3569-6163-6e26-bc0b39011924.png)

メインシーンに各シーンをロードするためのスクリプトも仕込んでおいた。
空のGameObjectをManagerという名前を付けて、それにくっつけた。

```csharp:SceneLoader.cs
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour {
	IEnumerator Start () {
		SceneManager.LoadScene("GameSelect", LoadSceneMode.Additive);
		SceneManager.LoadScene("Player", LoadSceneMode.Additive);

		yield return null;
	}
}
```

## カード部
カードはCubeで作成し、それぞれのカードをプレイヤーを中心に回転させる必要があったので、透明なCylinder(Rendererを無効)に子GameObjectとしてカードを紐づけるようにした。
カードは光る円盤上に存在するので、それっぽいパーティクルを付けた。
![009.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/e24d8366-7701-eb0b-dc7a-a342cd79935f.png)

あとは適当にクルクル回るようにスクリプトを作成した。

```csharp:GameRoll.cs
using UnityEngine;

public class GameRoll : MonoBehaviour {
	public GameObject cylinder;
	public bool isRoll;

	void Update () {
		if (isRoll)
		{
			var rotation = cylinder.transform.rotation;
			rotation *= Quaternion.Euler(0, -120 * Time.deltaTime, 0);
			cylinder.transform.rotation = rotation;
		}
	}
}
```

カードの絵は絵の担当にお願いして作ってもらい、そのままマテリアルに張り付けただけ。

## Air tapシステム
基本的にチュートリアルを移植している。
プレイヤーがどのカードを見ているか(選択するか)をGazeで決めるようにし、その見ているカードをAir tap Gesturesで選択するようにした。

GazeとAir tap Gesturesのチュートリアルは以下。
https://developer.microsoft.com/en-us/windows/holographic/holograms_101#chapter_2_-_gaze
https://developer.microsoft.com/en-us/windows/holographic/holograms_101#chapter_3_-_gestures

GazeではPhysicsRaycastを使っていて、Air tapをしたときに、Rayが当たっているものに対して、イベントを実行するようになっている。
今回は、回転を止めて、とりあえず選択したカードが落下するようにしている。(本当はプレイヤーに向かってくるようにしたかったけど時間切れのため)

```csharp:SphereCommands.cs
using UnityEngine;

public class SphereCommands : MonoBehaviour
{
	public GameRoll gameRoll;
	void OnSelect()
    {
        if (!this.GetComponent<Rigidbody>())
        {
			gameRoll.isRoll = false;
			var rigidbody = this.gameObject.AddComponent<Rigidbody>();
            rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
        }
    }
}
```

# 実行
おおまかに以上のような実装になる。
実際にアプリをHoloLensで実行するには、Unityでビルドし、Visual Studioでデプロイするようになる。

Unityでのビルドでは、プラットフォームをWindows Storeにし、SDKをUniversal 10、UWP Build TypeをD3Dにしてビルドする。
![010.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/e5f07895-c72f-a23c-2fc9-23c6ff24f5fe.png)

ビルドが完了した後、出力されたファイルの中のソリューションファイルをダブルクリックし、Visual Studioを起動する。
ソリューション構成をRelease、プラットフォームをx86にし、HoloLensをつなぎ、Deviceを選択して実行する。
![011.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/30f4d37a-ae6b-0b80-9ef7-e475d6c7c96c.png)

すると、HoloLensでUnityのスプラッシュ画面が出て実行されるようになる。はずなのだが…。

# うまくいかなかった点
## HoloLensでアプリが起動しない
まず、HoloLensで起動が出来なかった。
ハッカソン中ではチュートリアルのOrigamiをベースにして作り直したが、原因調査した結果、ProjectSettingsのPlayerのOtherにVRSupported項目があり、これにチェック入れ、SDK(Windows Holographic)を有効にする必要があった。
![012.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/a3e4fe1a-b4e7-f453-bc79-5bdbd7e51d9d.png)

チュートリアルではそれに触れていなかったので(Origamiはデフォルトで設定してあるため)、全然気づいていなかった…。

## Air tapで選択できない
カードをAir tapで選択させるところで、いくらAir tapしても反応がなかった。
ハッカソン中では結局解決せずに終わったが、原因調査した結果、カードを回転させるために親にしていたCylinderのCapsuleColliderが無効になってなかった。

PhysicsRaycastの衝突判定はColliderで行っているため、CylinderのColliderを有効にしたままだったので、衝突判定対象がCylinderになっていたためだった。

これを無効にしてやる必要がある。
![013.PNG](https://qiita-image-store.s3.amazonaws.com/0/141310/f6edf4be-1de7-ddbc-48d6-52d4120d15a4.png)

# 所感など
うまくいかなかった点はあったものの、HoloLensアプリを作って動かすのは全然難しくなく、背景などの空間を作る必要もないため、アプリ開発自体も手軽にできる感じだった。
その割には、実際にHoloLensで動いているアプリを見た時は、ちょっと感動した。現実世界に自分が作ったオブジェクトが動いているのは、すごく面白いと思った。
また、HoloLensのアプリ開発はHoloLensをつけたままビルドしたり、デプロイしたりできるので、VRより手間がかからないのもメリットに思えた。
今回作ったアプリは趣味というかお遊び要素の強いものだが、現実では表現できないものが表現出来たり、より実用的な(現実にそった)アプリも作れるので、MRは魅力的だなと思う。
まだそれなりの値段がするが、廉価版なども出てくるようなので、これから普及するものの一つになるだろうなということが体感できたハッカソンだったと思う。