CrossRoad

XRを中心とした技術ブログ。 Check also "English" category.

Holographic Academyの解説とTips紹介「Hologram 230- Spatial Mapping」

前回に引き続き、Holographic Academyについてです。今回は順番を飛ばしますが、Hologram 230 のSpatial Mappingについて整理しました。これまでの内容は下記にあります。

Holographic Academyの解説とTips紹介「Hologram 101」 - CrossRoad

Holographic Academyの解説とTips紹介「Hologram 210 - Gaze」 - CrossRoad

Holographic Academyの解説とTips紹介「Hologram 211 - Gesture」 - CrossRoad

0 準備

これまで通り、Windows 10のPCとHoloLensが必要です。また、Windows 10 PCの中には、Visual Studio Update3とUnity5.5以上がインストールされていることが必要です。

私の場合は、下記の環境で動作確認しました。

  • Windows10 Pro on Parallel Desktop 12.1.3 (MacはOSX 10.12.3)
  • Visual Studio Update3 (上記のWindows10 Proで動作)
  • Unity5.5.1f1 (上記のWindows10 Proで動作)

なお、「Hologram101」が未完の場合、先にChapter7のSpatial Mappingだけでも確認することをお勧めします。

まずは、「Holograms 230」を開き、プロジェクトをダウンロードします。

211のときと異なり、今回はチュートリアル確認用のプロジェクトは、unitypackageの形で提供されています。
(完成版はUnityプロジェクトです)

そのため、Unityで新規プロジェクトを作り、

Downloads\HolographicAcademy-Holograms-230-SpatialMapping\Starting からPlanetarium.unitypackageをインポートします。

これで始める準備は整いました。

1 Unity Setup

まずは一通りの環境を作ります。すでに何度か出てきている手順は割愛し、異なる手順だけ説明します。

(1) Capabilitiesの設定

AndroidでいうPermissionに相当します。今回の設定対象は、

InternetClientServer
PrivateNetworkClientServer
Microphone
SpatialPerception

です。
このように、Players Settingsの中で設定します。MicrophoneとSpatialPerceptionも同様です。

UnityでHologram230を使うときのCapabilitiesの設定画面

また、チュートリアルにも記載がありますが、BuildするときはC# Projectにチェックを入れておくことをお勧めします。

(2) Layerの設定

Cursor PrefabをHierarchy ViewにDrag & Dropしたら、Inspector ViewからLayer -> Add Layerを選びます。

UnityでHologram230を使うときのLayer設定画面

次に、指示に従ってUser Layer 31にSpatial Mapping と入力します。

新規Layerの入力画面
ただし、CursorのLayerは変更せずIgnore Raycastのままで良いです。

2 Chapter 1 - Scanning

ここでは、目の前でリアルタイムにメッシュを表示させる、という基本的な機能を解説しています。以下、チュートリアルの記載に沿って、3つに分けて説明します。

Build and Deploy (part 1)

まず、SpatialMapping PrefabをHierarchy ViewにDrag & Dropします。この時点でビルドしてHoloLens実機にアプリを転送すると、以下のようになります。


Build and Deploy (part 2)

2つ目では、UnityのProfiler機能を使ってGPUの負荷を見る方法を説明しています。Profilerは、UnityのWindow タブから開きます。

UnityのProfiler機能選択画面

開いたら、Active Profiler -> Enter IPを選択し、HoloLensのIPアドレスを入力します。

UnityのProfilerにてHoloLensのIPアドレスを入力する画面

すると、このようなグラフができます。

UnityのProfiler実行中画面
GPUの波形は、HoloLensが静止していれば穏やかですが、HoloLensが動けば(HoloLensを着けて辺りを見回せば)波形が変化します。

次に、Spatial Mapping Observerクラスの TrianglesPerCubicMeterを500から1200に変更してみます。Cubic単位のTriangleの数を変更、ということで、値を大きくするほどメッシュが細かくなりますが、モデル化するときのデータ量も多くなります。

SpatialMappingObserver.csを開いて、Awake()の先頭に下記を追加してビルドします。


gist5b6ac87c4bb728363469ed1054e40310

HoloLensで見てみると、よりメッシュが細かくなっていることが確認できます。


Save and load in Unity

3つ目の最後は、部屋の空間モデルをHoloLensから取得し、Unity Editorで見る方法を説明しています。まず、SpatialMappingObserver.csのAwakeに書いた下記は削除します。


gistc23a7b9a17cf7eb703d96fb36ccdc573

この状態で再度ビルドしてHoloLensにDeployします。アプリを起動後、PCのブラウザからDevice Portalを開きます。

■USB接続の場合

 ttp://127.0.0.1:10080 (hを追加してください)

■Wifi接続の場合

ttps://<HoloLensのIPアドレス> (hを追加してください)

Portalの3D ViewのSpatial Mappingという項目にあるUpdateをクリックします。1回クリックすると、空間のCG化が始まります。Portal上では何も変化が見られません。
HoloLensのDevice PortalのSpatial Mapping画面

再度Updateをクリックすると、その間に取得したモデルデータが反映されます。
HoloLensのDevice PortalのUpdateボタンを押したときの画面

次に、Saveをクリックすると、SpatialMapping.objという名前でダウンロードができます。
SpatialMappingのデータ保存画面
次に、SpatialMapping.objを先ほどのUnityのプロジェクトにドラッグします。

続けて、SpatialMapping オブジェクトのObject Surface Observer コンポーネントのRoom Modelにドラッグします。
SpatialMappingオブジェクトの設定手順

Unity Editorで再生すると、モデルを表示させることができます。ちなみに、WireFrameというshaderではこのように真っ暗です。
Unity Editorでモデルを表示した例

ShaderをStandardFastに変えると、見え方が変わります。
Shaderを変更したときのモデル表示例

Shaderの設定箇所は下記です。
Shaderの設定箇所

3 Chapter 2 - Visualization

ここでは、Shaderの加工によって、壁に相当する箇所だけ異なる表示にすることを説明しています。方法は簡単で、Spatial Mapping Manager コンポーネントのSurface Materialを、BlueLinesOnWallsに変更するだけです。Editorで見るとこうなります。

BlueLinesOnWallsを有効にして壁を検出した例
このShaderに設定してからHoloLensにビルドすると、壁が青く見えます。Chapter4で紹介する動画でBlueLinesOnWalls Shaderを使ってますので、見え方はそちらをご確認ください。

BlueLinesOnWallsのプロパティでは、線の太さと密度を変更できます。

■LineScaleを変更した場合

■LinesPerMeterを変更した場合


4 Chapter 3 - Processing

ここでは、Spatial Mappingで取得したモデルの中から壁と床を認識する処理を説明しています。今度は、SpatialProcessingと SpaceCollection Prefabを追加します。また、SpatialProcessingにアタッチされているPlaySpaceManager.csをチュートリアルに記載のコードと差し替え、Unity Editorで実行します。

最初はこのように真っ暗です。

Chapter3実行直後の画面

10秒たつと、壁と床を認識した箇所が別のGameObjectに置き換わり、かつプラネタリウムのようなモデルが中心に現れます。
Chapter3実行後に10秒程度経過した後の画面
実機でビルドしても同様です。

5 Chapter 4 - Placement

ここでは、AirTapによって、スキャンした空間の壁に、オブジェクトを配置する処理を説明しています。 SpatialProcessingオブジェクトのSurface Meshes To Planes コンポーネントのInspectorを見ます。

このように、Draw Planeの対象を修正し、Draw PlanesをEverythingからWallのみに変更します。

Surface Meshes To Planeコンポーネントの設定変更画面

なお、Destroy PlanesをUnknownから変更すると、今回のデモが動きませんのでご注意ください。ここでは、Placeable.csを修正します。チュートリアルに記載の完全版と差し替えます。

なお、Placeable.csはすでにProjecter、RocketPoster、AstronautPosterのPrefabにアタッチされています。

ビルドしてHoloLensで見てみます。

これまでのように10秒たってプラネタリウムが出たら、PosterとProjecterはGazeしてAirTapすることで移動させることができます。

このように、Placeable.csがアタッチされたオブジェクトであれば、AirTap後に自分の視線方向に移動させることができます。

移動開始と終了はAirTapです。

6 Chapter 5 - Occlusion

occludeの元々の意味は、塞ぐ、です。このChapterではHologramオブジェクトがSpatial Mappingのmeshにふさがれてしまう時に、どんな方法で表示させれば良いか、をデモで説明しています。

まず、HoloLensの世界ではオブジェクト同士が重なった時に4つの表現手段があります。ここでは、4つの表現手段を確認できるデモを作ります。

SpatialProcessing オブジェクトのPlay Space Manager コンポーネントでSecondary MaterialをOcclusionに変更します。
Play Space Manager コンポーネントの変更画面

次に、Solar System Prefabの中にあるEarthだけ、ShaderをOcculusionRimに変更します。
Solar System PrefabのShader変更画面

さらに、PlanetOcclusion.csを変更します。これは、SolarSystemの子オブジェクトである、それぞれの惑星Prefabにアタッチされています。

Holographic Academy230の該当箇所に完成版のコードがあります。ビルドしてHoloLensで動作を見てみます。通常のオブジェクトはそのまま見えます。 (Occlusion)

Earthの場合、他のオブジェクトの裏になると、青いふちだけに見えます。(Rim Shader)

他の惑星オブジェクトの場合、チュートリアルではX-rayと呼ばれる表示になります。 (Grid Shader)

また、惑星を取り巻く隕石は、壁の向こうに移動したり、何かの影になると隠れます。 (Occlusion)

7. Tips

いくつか気になるところがあったので、備忘録を兼ねて残しておきました。

7.1 Unity C#スクリプトは、HoloLens向けdeploy前のVisual Studioからも修正可能

Chapter1のBuild and Deploy (part 2)で出たTrianglesPerCubicMeterは、Spatial Mapping Observerクラスのpublic変数として指定されています。

通常のUnityでのアプリ開発の場合、Inspector Viewから値を変更します。しかし、Inspector Viewから変更すると、

1. UnityでビルドしてVisual Studioプロジェクトを生成

2, Visual Studio プロジェクトを開いて、HoloLensにDeploy

の2段階の手順が必要になります。

しかし、UnityでVisual Studioプロジェクトを生成する時に、Unity C# Project にチェックを入れておくと、Visual Studioで開いたときのプロジェクトにUhityで作ったソースコードが残ります。

さらに、ここでUnity C#のコードを修正してHoloLens向けにdeployすると変更が反映されます。Unityの画面でしかできない処理は対象外ですが、ある程度はこの方法でカバーできるので、ビルドの手間を減らす方法としてお勧めです。

7.2 Visual Studioで大量のエラーが出た場合、Nuget Packageの復元で修正できることがある

既存のVisual Studioプロジェクトからソースコードを開くと、自分が何もしていないのに大量のエラーメッセージが出ることがあります。

Visual Studioのプロジェクトを開いた直後のエラーログ

この場合、Nuget Packageの復元を実行することで直ります。
Nuget Packageの復元手順

これの原因はまだ調べきれてないですが、以前 Windows 10 Mobile向けのアプリを作ったときや、Microsoft提供のUWPサンプルプロジェクトを開いたときは、ほぼ100%発生しました。

7.3 実空間をSpatial Mappingで計測した結果を使って、オブジェクトを配置する方法

HoloLensアプリで、特定の壁や床から何かが飛び出してくるゲームを作る時は、あらかじめゲームを行う部屋をモデル化し、壁や床の位置を特定することが必要です。

そこで、今回取得したSpatialMapping.objを使うことで、オブジェクトの配置位置を決められるのかを試して見ました。まず、Unity上で取得したobjをHierarchy Viewにドラッグします。objになっている部屋の中に適当なgameobjectを配置します。今回は少し赤く色付けしたCubeを配置しました。
Unity Editor上でオブジェクトを配置した例

UWPビルドしてHoloLens実機に転送してみます。
HoloLensで実行したとき、オブジェクトがUnity Editorで指定した箇所に配置されている例

透過するので赤色がわかりづらいですが、Cubeの配置位置は、先ほどUnity上で配置した辺りと一致していました。特定の場所を使ったアプリを作りたい時は、こうやって事前スキャンした部屋モデルをUnityに読み込ませてから配置を検討すれば良さそうです。

ただし、注意点として、この方法を使う時は、アプリ起動時にUnityのCameraオブジェクトの向きとHoloLens実機の向きを一致させておく必要があります。

理由はわかりませんが、CameraとHoloLensの向きが不一致状態でアプリを起動すると、Cubeが見えませんでした。

ちなみに、先ほどObject Surface Observer コンポーネントにドラッグしたSpatialMapping.objは、そのままでビルドしても、HoloLensで見た時は表示されません。

7.4 Parallel DesktopではShaderにwarningが出ることがある

Chapter5では、OcculusionというShaderを使いました。これはParallel Desktop上のWindows10のUnityではwarningを表示していました。
Parallel Desktop上のWindows10のUnityでWarningを示す例

Windows 10 デスクトップPCでは出ませんでした。
Windows10のデスクトップでエラーが出ない例

ただし、Warningは出ますが、Parallel Desktopで作ってHoloLensにdeployしても動作は問題ありません。

8. 終わりに

Spatial Mappingは、HoloLensの最も分かりやすい特徴だと思います。実際、今回のデモではかなり色々と分かりました。ところで、今回、ざっとですがソースコードを見たところ、機能実現に必要なSpatialMappingObserver.csや、SpatialMappingManager.csは、具体的な処理を実行している部分は隠れていて、APIを呼び出すような形になっていました。

とはいえ、できることは色々あるはずなので、機能面ではもう少し調べた方が良いかもしれません。