先日、「FloorFalling MR」というアプリをWindowsストアに申請しました。複合現実を使って「自分の部屋の床が落ちる」という体験をするものです。(9/19現在、MSの審査は通ったのですが掲載ページが404になる状態です)
公開されました!
自分の部屋の床が落ちる #HoloLens アプリ、Windowsストアに申請しました!一発で承認されるかな?#WinMR pic.twitter.com/LEh5Ktq6fD
— とりカシュ💮 (@torikasyu) 2017年9月14日
初めは単に床が落ちるだけだったのですが、それだけだとエンタメ性が足りない、という社内のゲームプランナーの意見でいくつか要素を追加しました。結果、「部屋のどこかにいるユニティちゃんにたどり着けばゴールで、その途中の道だけは床が落ちない」という技術者(わたくし)泣かせの仕様になりました。
ということで、「FloorFalling MR」の作成に使用したコンポーネントや使用方法などをメモ的に記載しておきたいと思います。
まずは、UnityでのHoloLensアプリにほぼ必須のMixedRealityToolkit-Unity(旧 HoloToolkit-Unity)をインポートします。その中の下記のプレファブを使用します。
・HoloLensCamera
・InputManager
・BasicCursor
また、部屋の形を認識することが重要なので、
・SpatialMapping
・SpatialUnderstanding
も使用します。
SpatialMappingは空間の形状をメッシュにするもので、SpatialUnderstandingはそのメッシュの情報を使ってさらに高度なことをすることが可能です。
まずは「床」を認識する部分なのですが、SpatialMappingと、Toolkitに同梱されている「SurfaceMeshesToPlanes.cs」を使用します。この辺りは以前、下記の記事を書きましたのでご参照ください。
この床に、タイルとなるCubeを敷き詰めていきます。タイルの大きさと床の大きさがわかれば割り算で個数がわかるので、縦横のループでタイルをInstantiateするようにしました。そしてタイルの親オブジェクトのPosition、Rotationを床Cubeに合わせれば、床部分がタイルになります。
次は、ゴールとなるUnityちゃんを配置する方法です。HoloLensでスキャンした空間内にオブジェクトを配置するには、 SpatialMappingに加えて、SpatialUnderstandingを使用します。こちらも下記記事で解説しています。
// カメラを向いてもらう var dif = Camera.main.transform.position - unityChan.transform.position; var rot = Quaternion.LookRotation(new Vector3(dif.x, 0, dif.z)); unityChan.transform.rotation = rot;
そして、HoloLens装着者からUnityちゃんまでの道を作り、そこのブロックを落ちないようにする方法です。
ルートの計算にはNavMeshを使用しますが、今回はBakeできないので、動的NavMeshを使用します。
HoloLensでNavMeshといえば @tarukosuさん、@morio36さん、ということで、 下記の記事をご覧ください。
では、「落下する」という部分についてです。何かを落下させるにはRigidbodyをアタッチすればいいのですが、このままだとSpatialMappingの結果のメッシュが残っているので、それにぶつかって落下してくれません。メッシュ全体を消すことも可能なのですが、そうすると、壁などの障害物の情報もなくなってしまいます。また、あたり判定だけを消すこともできますが、そうすると床の下にある航空写真が見えなくなってしまいます。
なので、床部分だけを削除するのですが、これはToolkitに入っている「RemoveSurfaceVerticles.cs」で実現可能です。
メソッド RemoveSurfaceVerticesWithinBounds(IEnumerable
この「床ギリギリ」などのように、このアプリでは床のY座標を正確に取得することが重要となります。これも、SpataialUnderstandingでオブジェクトを配置するときと同じように、UnderstandingDLLを使用して取得できます。
float getFloorY() { // Alignment information SpatialUnderstandingDll.Imports.QueryPlayspaceAlignment(SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignmentPtr()); SpatialUnderstandingDll.Imports.PlayspaceAlignment alignment = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceAlignment(); return alignment.FloorYValue; }
ちなみに、下記のような「床に穴をあける」タイプですと、凹みさんのシェーダーが大活躍します。
夏休みなのに雨なので自宅で高所恐怖Showをやってみた #holoLens pic.twitter.com/Vul4DdbcfG
— とりカシュ💮 (@torikasyu) 2017年8月15日
というわけで、皆様のブログや調査結果を使ってなんとか実現することができました。感謝!