UnityによるHoloLens
アプリケーション入門
石井勇一 2018/03(2018/04/04公開版)
0. はじめに
(C) 2018 石井 勇一 2
研修の概要
本研修はUnityによるHoloLensアプリケーションの作成に必要な基礎知識を身につけるための
必要な機能について紹介します。
◦ Unityが提供する多種多様なプラットフォーム対応を説明できる
◦ Unityの基本概念を理解して基本的な操作ができる
◦ Unityの基本コンポーネントとその制御スクリプトを簡単な物であれば自作できる
◦ HoloLensアプリケーションを作るために必要な機能について把握し、適切な提案ができる
(C) 2018 石井 勇一 3
使用しているソフトウェアについて
ソフトウェア名 バージョン
Unity Unity 2017.2.1.p1(MRTK対応バージョン)
PC Windows 10 Fall Creators Update必須
Visual Studio 2017
MixedRealityToolkit‐Unity 2017.2.1.3 Hot Fix
https://github.com/Microsoft/MixedRealityToolkit‐Unity/releases
(C) 2018 石井 勇一 4
目次
1. HoloLensアプリ開発入門
1. MixedRealityToolkit‐Unity とは
2. Input(Gaze/AirTap/Voiceなど)
3. Spatial Sound
4. Spatial Mapping
5. UX Controls
6. Spatial Understanding
7. Sharing
8. その他便利な機能や情報
(C) 2018 石井 勇一 5
1.HoloLensアプリ開発入
(C) 2018 石井 勇一 6
HoloLens
HoloLensのハードウェア仕様
◦ https://developer.microsoft.com/en‐us/windows/mixed‐reality/hololens_hardware_details
◦ CPU: Intel 32 bit architecture
◦ GPU: HPU 1.0 (HoloLens専用に開発)
◦ RAM: 2GB
◦ Flash: 64GB
◦ Sensors: Depth Camera, Ambient light sensor, Image camera
◦ ETC: Bluetooth 4.0LE / Wi‐Fi 802.11ac / Speaker / Microphone
OS: Windows 10 (Universal Windows Platform)
(C) 2018 石井 勇一 7
HoloLensアプリ開発の流れ
1. UnityでWindows Store(Universal Windows Platform向け)に切り替えて開発
2. UnityからVisual Studioプロジェクトファイルの作成
3. Visual Studioでx86版のアプリをビルド&配備(HoloLensにインストール)
(C) 2018 石井 勇一 8
(参考): UWPとは
ユニバーサル Windows プラットフォーム (UWP) アプリとは
◦ https://docs.microsoft.com/ja‐jp/windows/uwp/get‐started/whats‐a‐uwp
(C) 2018 石井 勇一 9
Unity標準機能によるHoloLens用設定
新規にプロジェクトを作成
プロジェクトの設定
◦ File > Build &  Settingsを実行
◦ Universal Windows Platformに切り替え
◦ Player Settingsボタンを押す
◦ Other Settingsの「Scripting Backend」を.NETに変
更
◦ XR Settingsの「Virtual Reality Supported」を
チェック。これでWindows Mixed Realityが選択さ
れている
◦ Edit > Project Settings > Qualityを実行
◦ Universal Windows Platformの設定をVery Low
に変更
(C) 2018 石井 勇一
ここをクリック
10
Unity標準機能によるHoloLens用設定
シーンの設定
◦ Main CameraのTransformコンポーネントの歯車アイコンをク
リックして「Reset」を実行
◦ Main CameraのCameraのClear FlagsをSolid Colorに変更
◦ Main CameraのCameraのBackgroundを黒(0, 0, 0)に変更
◦ Main CameraのCameraのClipping PlanesのNearを0.85に変更
以上の設定を毎プロジェクトごとに実施しなければならな
いのでMRTKを使って一気に設定をする方法を紹介します。
(C) 2018 石井 勇一 11
HoloLensのためのカメラ設定
快適なカメラの設定
https://developer.microsoft.com/en‐us/windows/mixed‐reality/comfort
(C) 2018 石井 勇一 12
HoloLensのためのカメラ設定
HoloLensのディスプレイは「光の加算」
◦ 白色:明るく見える
◦ 黒色:透明に見える
黒が透明になる特性を活かして、実際に描画する3Dオブジェクト以外は黒にする
ライティングや色に関する詳細情報
◦ https://developer.microsoft.com/en‐us/windows/mixed‐reality/color,_light_and_materials
(C) 2018 石井 勇一 13
Cubeを配置
物を配置する適切な位置
https://developer.microsoft.com/en‐us/windows/mixed‐reality/gaze_targeting
(C) 2018 石井 勇一 14
Cubeを配置
[GameObject]‐[3D Object]‐[Cube]でCubeを配置
InspectorのTransformコンポーネント
◦ Position:  0, 0, 2 (前方2m先)
◦ Scale: 0.1, 0.1, 0.1(全体的に10分の1にする)
UnityのCubeは一辺が1mの立方体です。そのスケールを0.1倍するので、一辺が10cmの立方
体になります。
(C) 2018 石井 勇一 15
1.1 MixedRealityToolkit‐
Unity とは
(C) 2018 石井 勇一 16
MixedRealityToolkit‐Unity
Mixed Reality Toolkitは、Microsoft HoloLensとWindows Mixed Realityヘッドセットを対象とした
アプリケーション開発のためのスクリプトとコンポーネントの集まりです。
MixedRealityToolkit ‐ UnityはMixedRealityToolkitベースのコードを使用しており、さらにUnityで
簡単に利用できるようになっています。
(C) 2018 石井 勇一 17
(C) 2018 石井 勇一 18
提供機能概要(HoloLens限定)
Input
◦ 視線(Gaze)、ジェスチャー、音声およびモーションコントローラなどの入力を活かすスクリプト。
Spatial Mapping
◦ HoloLensを使用して実際の世界にデジタルを持ち込むためのスクリプト。
Spatial Sound
◦ 空間オーディオをアプリケーションで実現するためのスクリプト。
(C) 2018 石井 勇一 19
提供機能概要(HoloLens限定)
UX Controls
◦ 共通のコントロールのように、アプリケーションにより良いUXを作成するための部品
Spatial Understanding
◦ ソファや壁などの部屋を「理解する」ためのスクリプト
Sharing
◦ 複数のHoloLesnで同一の映像を見ることで共同作業を可能にします。
(C) 2018 石井 勇一 20
MRTKの導入と初期設定
Unityで新規にプロジェクトの作成
HoloToolkit‐Unity‐2017.2.1.3.unitypackageをインポート
Mixed Reality Toolkit > Configure > Apply Mixed Reality Project Settingsを実行
(C) 2018 石井 勇一 21
MRTKの導入と初期設定
HoloLensの場合はそのままApplyをクリック
これで P.8 で紹介した内容の設定が完了しま
す。
それぞれの説明は次ページ以降で紹介。
(C) 2018 石井 勇一 22
MRTKの導入と初期設定
Target Windows Universal UWP
◦ Universal Windows Platformをターゲットとする
Storeアプリケーションに切り替えます。
Enable XR
◦ Mixed Reality Supportを有効にします。
Build for Direct3D
◦ XAMLではなくDirect3Dをターゲットとするアプリ
ケーションを作成します。
Target Occluded Devices
◦ VR hardwareの場合はチェックし、HoloLensの場
合はチェックを外します。
(C) 2018 石井 勇一 23
MRTKの導入と初期設定
Enable Sharing Services
◦ Sharing機能を使うときに有効にします。あとから
も設定を変えられます。
Use Toolkit‐specific InputManager axes
◦ Xboxコントローラを使用するときはチェックする。
Project Settings/Inputの定義ファイルを上書き
するので注意
Enable .NET scripting backend
◦ Scripting backendを .NETに変更する
(C) 2018 石井 勇一 24
MRTKの導入と初期設定
シーンファイルを初期化
Mixed Reality Toolkit > Configure > Apply Mixed Reality Scene Settingsを実行
(C) 2018 石井 勇一 25
MRTKの導入と初期設定
HoloLensの場合はそのままApplyをクリック
これで P.9 で紹介した内容の設定が完了しま
す。
ですが、バグがあるので上手く動きません。
https://github.com/Microsoft/MixedRealityTo
olkit‐Unity/issues/1790
これを修正するパッチはまだないのでこちら
で用意しました。
(C) 2018 石井 勇一 26
MRTKの導入と初期設定
参考:Hierarchy のMixedRealityCameraParent
の子要素のMixedRealityCameraにアタッチさ
れているMixedRealityCameraManagerが実行
時にカメラの設定を変更します。
◦ CameraのClear FlagsをSolid Colorに変更
◦ CameraのBackgroundを黒(0, 0, 0)に変更
◦ CameraのClipping PlanesのNearを0.85に変更
ただし、これはUnity上でプレイボタンを押し
たときは「Opaque」扱いになるためSkybox+
QualityセッティングがUltraになってしまいます。
場合によってはこのスクリプトを無効化して手
動で設定することも考慮に入れてください。
Hierarchy View
(C) 2018 石井 勇一 27
MRTKの導入と初期設定
Add the Mixed Reality Camera Prefab
◦ Mixed Reality Camera プレハブをシーンに追加します。本
来ならそのままで動作しますが、
Move Camera to Origin
◦ カメラの位置を(0, 0, 0)に設定します。
Add the Input Manager Prefab
◦ Input Managerプレハブを追加します。
Add the Default Cursor Prefab
◦ Default Cursorプレハブを追加します。
Update World Space Canvases
◦ 全てのWorld SpaceのCanvasに対して視線からのイベント
を受け取れるようにUIRaycastCameraをデフォルトイベント
カメラとして使用します。
◦ 以後もCanvasをWorld Space に変えると自動的に追加お
よび設定をします。
(C) 2018 石井 勇一 28
Cubeを配置
何も無いと寂しいのでCubeを配置しましょう。
位置やスケールは以下の通りにします。
◦ Position(0, 0, 2)
◦ Scale(0.1, 0.1, 0.1)
(C) 2018 石井 勇一 29
Unity Editor上で動作させる
そのままPlayボタンを押すとUnity Editor上でも動作させることができます。
Unity Editor上での操作
◦ 移動:マウスの右ボタンを押しながらWASDおよびQEキー
◦ 視線:マウスの右ボタンを押しながら動かす
◦ AirTap: マウスのボタンから手をいったん離し、Shiftキーを押しながらマウスの左ボタン
Cubeに視線を合わせたり、外したり、AirTapしてみましょう
Skyboxが表示されていますが問題ありません(実機に転送したり、リモート接続、 Simulate
モードの時は自動的にHoloLens用にCameraの設定を変更します)
(C) 2018 石井 勇一 30
アプリケーションのビルド方法
本来であればメニューのMixed Reality Toolkit > Build Windowの画面から適切な設定をするこ
とでビルドおよびHoloLensへの配信が出来るようになっていますが、Visual Studioの内部バー
ジョンの変更に伴い上手く動作しないことが多いです。
そのため少々手間ですが、Visual Studioを経由する方法を紹介します。
(C) 2018 石井 勇一 31
アプリケーションのビルド方法
Sceneの保存(Ctrl+S)、Projectの保存(File > 
Save Project)は確実に実施する
File > Build Settingsを開く
Buildボタンを押す(Build & Runではない)
(C) 2018 石井 勇一 32
アプリケーションのビルド方法
UWPでは直接アプリケーションのビルドは行
わずに、一度Visual Studio用のプロジェクト
ファイル一式を生成します。
ここではそれらを格納するフォルダ名を指定
します。
お勧めは「新しいフォルダー」でフォルダを作
成してそこに格納する方法です。
名前は何でも良いですが、ここでは「App」と
します。
フォルダを選択したら「フォルダの選択」ボタ
ンを押す
(C) 2018 石井 勇一
Appフォルダを作成してそれを指定する
33
アプリケーションのビルド方法
しばらくすると図の用の先ほど選択したフォ
ルダを表示するようにエクスプローラーが起
動します。
選択したフォルダ(App)の中に移動します。
(C) 2018 石井 勇一 34
アプリケーションのビルド方法
フォルダの中に「Unityのプロジェクト名.sln」と
いう名前のVisual Studio用のソリューション
ファイルがありますのでそれをダブルクリック
します。
(C) 2018 石井 勇一 35
アプリケーションのビルド方法
ビルドターゲットを「Release」、「x86」、「Device」に変更します。
(C) 2018 石井 勇一 36
アプリケーションのビルド方法
ReleaseにするのはDebug版では性能が出ないためです。
x86にするのはHoloLensが32bit版 IntelアーキテクチャCPUだからです(ATOM)
DeviceにするのはHoloLensがUSBケーブルでPCに繋がっているときに奏します。
PC/HoloLensともに同一ネットワークにつながっている場合は「リモートコンピューター」を選び、
HoloLensのIPアドレスを入力することでケーブルレスで繋げることもできます。
(C) 2018 石井 勇一 37
HoloLens開発者モード
HoloLensを起動
メニューの中から「Settings」を実行
(C) 2018 石井 勇一 38
HoloLens開発者モード
「Update & Security」を実行
(C) 2018 石井 勇一 39
HoloLens開発者モード
「For developer」を実行
(C) 2018 石井 勇一 40
HoloLens開発者モード
Developer modeを「On」にする
(C) 2018 石井 勇一 41
HoloLens開発者モード
Device Portalを「On」にする
(C) 2018 石井 勇一 42
HoloLensの設定
HoloLensをUSBケーブルでPCに接続
Edge(Webブラウザ)を起動
以下のURLを開く(HoloLens内に実装されているDevice Portalへアクセスする)
◦ http://127.0.0.1:10080/
初回接続時はユーザ名とパスワード(パスワードは最低7文字以上)の作成をする。その際、
HoloLensに表示されているPINを使用する
裏技:もし誰かがユーザー登録していたとしても、5回連続間違えることでユーザー名とパス
ワードを再設定できます。
(C) 2018 石井 勇一 43
HoloLensの設定
Device Portal画面
(C) 2018 石井 勇一 44
Visual Studioによる操作
Visual Studioの上部にあるDebug / ARM / Deviceを以下のようにに修正してください。
(C) 2018 石井 勇一 45
Visual Studioによる操作
[デバッグ]‐[デバッグなしで開始]またはCtrl + F5を押してコンパイル&リンク&配置(インストー
ル)&実行をします。
それなりに時間が掛かります。その間にHoloLensがスリープしないように注意してください
(Device Portalでスリープするまでの時間を変更できます)。
(C) 2018 石井 勇一 46
Visual Studioによる操作
もし途中でPINを聞かれた、HoloLensのSettingsの[Update & Security]‐[For Developer]のPaired 
devicesの[Pair]ボタンを押して出てきた数字を入力して下さい。
(C) 2018 石井 勇一 47
Visual Studioによる操作
Visual Studioへの入力が終
わり、ボタンが「Done」に変
わったらクリックして閉じる
(C) 2018 石井 勇一 48
実行結果
2m先に一辺が10cmの立方体が表示されるはずです
(C) 2018 石井 勇一 49
Holographic Remoting Player
Unity上での再生でもある程度操作ができますが実機でテストしたくなることも多いです。
しかし、実機でテストするにはそれなりビルド時間が掛かります。
「Holographic Remoting Player」を使う事でこれらの問題点をある程度解決できます。
https://developer.microsoft.com/en‐us/windows/mixed‐reality/holographic_remoting_player
PC側のシステム要件
◦ Windows 10 Anniversary Update以降必須(現在はFall Creators Update)
◦ GeForce GTX 970 または AMD Radeon R9 290以上のグラフィックボード
◦ PCは可能であれば有線接続にして不要なホップ数を減らすことを推奨
(C) 2018 石井 勇一 50
Holographic Remoting Playerの使い方
HoloLensのストアから「Holographic Remoting Player」を探してインストールする
◦ https://www.microsoft.com/ja‐jp/store/p/holographic‐remoting‐player/9nblggh4sv40
アプリを起動すると図のような画面が表示される。このときのIPアドレスを覚える
(C) 2018 石井 勇一 51
Holographic Remoting Playerの使い方
Unityの[Window]‐[Holographic Emulation]を開く
HolographicウィンドウのEmulation Modeを
「Remote to Device」に変更
先ほど覚えたHoloLensのIPアドレスを「Remote 
Machine」に入力
[Connect]ボタンを押す。
小技:このとき上手くつながらないことがあります。
その場合、「Enable Audio」のチェックを一度外し
てから再度「Connect」ボタンを押して繋げて、
「Disconnect」してから再度「Enable Audio」をチェッ
クしてから「Connect」ボタンを押すと繋がることが
あります。あと音声は重たい様なのでビットレート
(一番下のスライドバー)を下げると良いかも知れ
ません。
(C) 2018 石井 勇一 52
Holographic Remoting Player利用時の
注意点
全体的に不安定です(特にUnity側)。そのためこまめにプロジェクトやシーンファイルのセーブ
を忘れずに。
Unity Editor上でエミュレーションをするならHolographicウィンドウのEmulation Modeを
「Simulate in Editor」にする方法もあります。その際、Unity Editor内におけるHoloLensの動きは
ジョイパッドを使用します。
◦ https://docs.unity3d.com/ja/current/Manual/windowsholographic‐emulation.html
(C) 2018 石井 勇一 53
1.2 Input
GAZE/AIRTAP/VOICEなど
(C) 2018 石井 勇一 54
Gaze(視線)
HoloLensの基本的な入力はGaze(視線)になります。
目標
◦ カーソルのビジュアル デザインと動作
◦ 視線に応じたカーソルのフィードバック
◦ 視線に応じたホログラムのフィードバック
カーソルのデザイン原則
◦ カーソルは常時表示します。
◦ カーソルは適切なサイズに保ちます。
◦ コンテンツの邪魔にならないようにします。
(C) 2018 石井 勇一 55
視線はレイキャスト
始点から直線を伸ばしてその途中に何かが衝突するかどうかを調べる機能
始点
距離
ヒット
(C) 2018 石井 勇一
ヒット
しない
56
© UTJ/UCL
InputManager
視線に関する設定はInputManagerに適用されているGaze Managerで行います。
最大距離は「Max Gaze Collision Distance」で設定します(単位はm)
(C) 2018 石井 勇一 57
視線カーソル関連のプレハブ
特に凝ったことをしなければシーンにプレハブを入れるだけで利用可能です。
格納場所は Assets/HoloToolkit/Input/Prefabs/Cursor です。
利用可能なプレハブは次のスライドを参照
(C) 2018 石井 勇一 58
視線カーソル関連のプレハブ
BasicCursor.prefab
◦ ユーザーの視線に沿ったトーラス型(ドーナッツ型)の基本カーソル。
Cursor.prefab
◦ ユーザがホログラムを注視しているときにトーラス型、ホログラムへの注視が外れると半透明な球体
の形のカーソルに変わります。
CursorWithFeedback.prefab
◦ ユーザーの視線に沿ったトーラス型のカーソルに加えて、手を認識すると指のアイコンを表示する。
DefaultCursor.prefab
◦ ユーザーの視線に沿った3Dアニメーションカーソル。Unityのアニメーションシステムを使用してさまざ
まな状態を処理します。 このカーソルは、HoloLensシェルのカーソルを模倣します。
(C) 2018 石井 勇一 59
Gaze関連イベント処理
注視されたときにイベントを発生させるためには以下のインタフェースを実装したスクリプトを
作成します。
IFocusable
(C) 2018 石井 勇一 60
public interface IFocusable : IEventSystemHandler
{
void OnFocusEnter(); //フォーカス(注視)し始めたとき時
void OnFocusExit(); // フォーカス(注視)が外れた
}
Gaze関連イベント処理
プログラム例
(C) 2018 石井 勇一 61
using UnityEngine;
using HoloToolkit.Unity.InputModule;
// IFocusableインタフェースを実装することで、注視された時とはずれたときにそれぞれメソッドが呼び出される
public class GreetingUnitychan : MonoBehaviour, IFocusable {
private Animator anim;
void Start()
{
anim = GetComponent<Animator>();
}
// フォーカス(注視)し始めたとき時
public void OnFocusEnter()
{
anim.SetTrigger("Greeting");
}
// フォーカス(注視)が外れた
public void OnFocusExit()
{
// 今回は特に実装無し
}
}
ジェスチャー関連のイベント
様々なジェスチャーが発生した時に対応する処理を書くには以下のインタフェースを実装します。
IInputHandler
◦ オブジェクトへのInputDown / 対象へのInputUp
IInputClickHandler
◦ オブジェクトへのクリックイベント(AirTap)
ISourceStateHandler
◦ 手の検出。対象を見ている状態で手が認識されている / 対象を見ている状態で手が認識から外れた
IHoldHandle
◦ ホールドの検出。対象をつまみだした / 対象をつまんでいる / 対象をつまみ外した
IManipulationHandler
◦ ドラッグ操作。対象をつまみだした / 対象をつまんでいる / 対象をつまみ外した / 途中でトラッキングが外れ
た
INavigationHandler
◦ ナビゲーション操作。対象をつまみだした / 対象をつまんでいる / 対象をつまみ外した / 途中でトラッキング
が外れた
(C) 2018 石井 勇一 62
IInputHandlerインタフェース
インタフェース
(C) 2018 石井 勇一 63
public interface IInputHandler : IEventSystemHandler
{
void OnInputDown(InputEventData eventData);
void OnInputUp(InputEventData eventData);
}
IInputClickHandlerインタフェース
インタフェース
(C) 2018 石井 勇一 64
public interface IInputClickHandler : IEventSystemHandler
{
void OnInputClicked(InputClickedEventData eventData);
}
ISourceStateHandlerインタフェース
インタフェース
(C) 2018 石井 勇一 65
public interface ISourceStateHandler : IEventSystemHandler
{
void OnSourceDetected(SourceStateEventData eventData);
void OnSourceLost(SourceStateEventData eventData);
}
IHoldHandleインタフェース
インタフェース
(C) 2018 石井 勇一 66
public interface IHoldHandler : IEventSystemHandler
{
void OnHoldStarted(HoldEventData eventData);
void OnHoldCompleted(HoldEventData eventData);
void OnHoldCanceled(HoldEventData eventData);
}
IManipulationHandlerインタフェース
インタフェース
(C) 2018 石井 勇一 67
public interface IManipulationHandler : IEventSystemHandler
{
void OnManipulationStarted(ManipulationEventData eventData);
void OnManipulationUpdated(ManipulationEventData eventData);
void OnManipulationCompleted(ManipulationEventData eventData);
void OnManipulationCanceled(ManipulationEventData eventData);
}
INavigationHandlerインタフェース
インタフェース
(C) 2018 石井 勇一 68
public interface INavigationHandler : IEventSystemHandler
{
void OnNavigationStarted(NavigationEventData eventData);
void OnNavigationUpdated(NavigationEventData eventData);
void OnNavigationCompleted(NavigationEventData eventData);
void OnNavigationCanceled(NavigationEventData eventData);
}
実装例
AirTapによって自分自身を消す
(C) 2018 石井 勇一 69
using HoloToolkit.Unity.InputModule;
using UnityEngine;
// IInputClickHandlerを実装することで、注視&クリック(AirTap)時に呼び出されるメソッドが呼び出される
public class HideCube : MonoBehaviour, IInputClickHandler {
// 注視&クリック(AirTap)されると呼び出される
public void OnInputClicked(InputClickedEventData eventData)
{
// 自分自身の削除
Destroy(gameObject);
}
}
何も無い所をAirTapした時のイベントを
取得するには
InputManager.Instance.AddGlobalListener()に登録する
(C) 2018 石井 勇一 70
using HoloToolkit.Unity.InputModule;
using UnityEngine;
public class NothingSpaceClickHandler : MonoBehaviour, IInputClickHandler {
void Start () {
// 全てのジェスチャーイベントをキャッチできるようにする
InputManager.Instance.AddGlobalListener(gameObject);
}
/// AirTapイベントのハンドラ
public void OnInputClicked(InputClickedEventData eventData) {
// 何もGazeしていないときだけ動作する
if (!GazeManager.Instance.HitObject) {
// ログを吐くだけ
Debug.Log("Click on nothing point !!!!");
}
}
}
参考: http://blog.d‐yama7.com/archives/699
その他のイベントについて
HoloLens+Unity開発 入力の取得まとめ編 by のしメモ アプリ開発ブログ
http://www.noshimemo.com/entry/2017/01/28/133818
HoloLesnに対する操作とそれに対応するイベント発生を一つにまとめている動画がとても分か
りやすい。
(C) 2018 石井 勇一 71
1.3 Spatial Sound
(C) 2018 石井 勇一 72
空間音響
英語はSpatial Sound と言います。
HoloLensは実際の空間で数メートル先に物体を表示します。
そして、HoloLensはそこから音が発生しているかのように振舞うことができます。
(C) 2018 石井 勇一 73
Unityの設定
[Edit]‐[Project Settings]‐[Audio]を開く
Spatializer Pluginを「MS HRTF Spatializer」に
変更
(C) 2018 石井 勇一 74
HRTF: 頭部伝達関数(Head-Related Impulse Response)
ユニティちゃんの設定
Audio Sourceコンポーネントを追加
設定を変更
◦ Spatializeをチェック
◦ Play On Awakeのチェックを外す
◦ Spatial Blendを1(3D)
◦ 3D Sound Settingsを変更(次のスライド)
(C) 2018 石井 勇一 75
ユニティちゃんの設定
AudioSourceの設定の続き
◦ Doppler Levelを0
◦ Max Distanceを20
(C) 2018 石井 勇一 76
ユニティちゃんの設定
PlayAudioClipスクリプトを追加
(Assets/UnityCHan/Custom/Scripts/PlayAudioClip)
Audio Clipsを0から3に変更してEnterキーを押す
(C) 2018 石井 勇一 77
ユニティちゃんの設定
PlayAudioClipの設定の続き
◦ Element0~2に適当なAudio Clip(音声ファイル)をドラッグ&ドロップで設定する
◦ Assets/UnityChan/unitychan_voicepack_append_01に音声ファイルがあります。
(C) 2018 石井 勇一 78
Unity上で実行
Playボタンを押してみましょう。
ユニティちゃんに視線を合わせてAirTapすると設定した音声のどれかをランダムで喋ります。
動作が確認出来たらHoloLensにインストールして動作確認してみましょう。HoloLensでは空間
音響が試せるので、USBケーブルと人とPCに注意しながら移動したり顔を左右に振ってみて下
さい。
(C) 2018 石井 勇一 79
応用
長時間再生する音声ファイルがあります。
Assets/UnityChan/Unite In The Sky (full)
これをAirTapで再生停止できるCubeを作成してみましょう(図で示しているサンプルコードを参
照)
音声が少し大きいのでAudio Sourceの設定でVolumeを1から0.3などに変更するとよいでしょう。
音声の再生が始まったら近づいたり、離れたり、左右に頭を振ると空間音響の効果がよりはっ
きりと分かると思います。
(C) 2018 石井 勇一 80
応用
HoloLesn用に用意されているスクリプトがいくつかあります。
AudioEmitter.cs
◦ AudioSourceをカプセル化し、オーディオの影響(オクルージョンなど)の適用をサポートするクラスです。
AudioOccluder.cs
◦ ローパスフィルタと音量減衰を使用した簡単な形式のオーディオオクルージョンを実装するクラス。
IAudioInfluencer.cs
◦ AudioInfluencerに必要なメソッドを定義するインターフェース。 AudioOccluder.csで使用。
UAudioManager/UAudioManager.cs
◦ オーディオ全般を管理するクラス
(C) 2018 石井 勇一 81
応用
利用イメージ
(C) 2018 石井 勇一 82
AudioOccluder
AudioEmitterAudioEmitter
減衰して
聞こえる
何も影響を
受けずに聞こえる
© UTJ/UCL
AudioEmitter.cs
Update Interval
◦ オーディオへの影響の更新間隔(秒単位)。 0はすべてのフレームを更新することを示します。
Max Distance
◦ 最大距離 (単位はm)。
Max Objects
◦ 影響を受けるオブジェクトの最大数。
(C) 2018 石井 勇一 83
AudioOccluder.cs
Cutoff Frequency
◦ ユーザーと AudioEmitter の間にある時に適用される最低周波数。
Volume Pass Through
◦ ユーザーと AudioEmitter の間にある時の音量の割合。
(C) 2018 石井 勇一 84
応用
CubeにAudioEmitter.csをアタッチ
新たにCubeを作成して、Wallと名前を付ける。分かりやすく適当にマテリアルを作成して色を
付ける
Wallの位置とスケールを調整
◦ Position(0, 0, 1.5)
◦ Scale(0.3, 0.5, 0.05)
WallにAudioOccluder.csをアタッチ
AudioOccluderの値を以下のように修正
◦ Cutoff Frequency: 600
◦ Volume Pass Through: 0.5
(C) 2018 石井 勇一 85
応用
Remote Playで試す場合はUnity Editorのシー
ンビューでWallを左右にずらすと効果が分か
ります。
実機に転送した場合はWallを回り込むとそ
の効果が分かります。
(C) 2018 石井 勇一 86
応用
UAudioManager.csを使うと、それぞれの音声を「AudioEvent」として名前を付けて、様々な設定
をまとめて管理できます。
(C) 2018 石井 勇一 87
UAudioManager
(Singletone)
Audio Bank
(ScriptableObject)
Audio Bank
(ScriptableObject)
Audio Event Bank
(ScriptableObject)
音声を再生する
スクリプト
音声の再生を依頼音声の再生方法を設定
Audio Event Bankを管理
Audio Bankの作成方法
Project Viewで右クリックして、Create > Audio Event Bankをクリック
「AudioEventBank」ファイルが生成される
(C) 2018 石井 勇一 88
Audio Bankの設定
Audio Bankファイルを選択し、インスペクターからEventのAddボタンを押す
(C) 2018 石井 勇一 89
Audio Bankの設定
設定例
◦ NameはUAudioManager経由で再生するスクリ
プトで指定する名前になります。 "/"を含めると
サブメニューにすることができます。
◦ Positioningを「Spatial Sound」にすると空間音響
になる。他にも2D/3Dなどもある。
◦ Audio Event Interface Behaviorは音声ファイル
の生成上限数(Instance Limit)を超えたときのア
ルゴリズムを選択。Kill Oldestは古い音を止めて
再利用。Kill Newestは新しい音を止めて再利用。
(C) 2018 石井 勇一 90
UAudioManagerの設定
適当なGameObjectを作成してそこにアタッチする。
Default Banksを1以上の値にする(Audio Bank数分作成)
作成したAudio Bankをセットする
(C) 2018 石井 勇一 91
再生スクリプト
HoloToolkit‐Unity‐Examples‐2017.2.1.3のUAudioManagerTestを参照
(C) 2018 石井 勇一 92
public class UAudioManagerTest : MonoBehaviour
{
[AudioEvent]
public string Vocals3d;
[AudioEvent]を付けておくと、
インスペクターからプルダウ
ンメニューで選択できます。
UAudioManager.Instance.PlayEvent(Vocals3d);
UAudioManager.InstanceでUAudioManagerのインス
タンスを取得できます。PlayEvent()で音声を再生
します。AudioSourceコンポーネントは無ければ自
動的に追加します。
第二引数にAudioSourceコンポーネントへの参照を
指定するとそちらを使用します。
(C) 2018 石井 勇一 93
1.4 Spatial Mapping
(C) 2018 石井 勇一 94
Spatial Mappingとは
HoloLensに搭載している複数のカメラを駆使して現実空間をリアルタイムにスキャンし、システ
ム内に3Dモデルデータとして保存する機能です。データは逐次更新されます。
アプリケーションからも利用することができます。作成した3Dモデルデータにはコライダーが設
定されています。
(C) 2018 石井 勇一 95
Spatial Mappingを使う設定
[Mixed Reality Toolkit]‐[Configure]‐[Apply UWP Capability Settings]を実行(Capability=能力)
(C) 2018 石井 勇一 96
Spatial Mappingを使う設定
Spatial Perceptionをチェックして「Apply」ボタ
ンを押す
その他のは「マイク」「カメラ(Webcam)」「イン
ターネット接続(クライアントとサーバ)」などを
利用するときに同様の設定をします。
(C) 2018 石井 勇一 97
【参考】UWPのCapabilityの設定
[Editor]‐[Project Settings]‐[Player]の
Publishing Settingsの下の方にCapabilitiesの
設定があります。ここで設定してもOKです。
(C) 2018 石井 勇一 98
Spatial Mappingを使う設定
Assets/HoloToolkit/SpatialMapping/Prefabsにある
SpatialMappingをHierarchyにドラッグ&ドロップする
Unityではテストするときは、Holographicウィンドウで
Emulation ModeをSimulate in Editorにし、適当なRoom
を選択してください。
空間のスキャンは3.5秒間隔で行われますのでゆっく
りと周りを見渡してください。
十分にスキャンが出来たと思ったらユニティちゃんの
床にあるCubeをAirTapしてユニティちゃんを落下させ
てください。
上手くいくと床の上でユニティちゃんがとまります。机
の影になるように回り込むと、きちんと見えなくなると
思います。
(C) 2018 石井 勇一 99
Spatial Mappingを使う設定
Unityではテストするときは、HolographicウィンドウでEmulation ModeをSimulate in Editorにし、
適当なRoomを選択してください。
あるいはEmulation ModeをNoneにして、 SpatialMappingにアタッチされている
ObjectSurfaceObserverのRoom Modelの右の◎ボタンを押して、
「MediumRoomWithHomeFurniture」を選択してから実行してください。これでダミールームデー
タによるスキャン実験ができます。
(C) 2018 石井 勇一 100
クラス図
(C) 2018 石井 勇一 101
SpatialMappingSource
SpatialMappingObserver
SpatialMappingManager
(Singleton)
ObjectSurfaceObserver
SpatialMappingObserverを操作するためのクラス
・スキャンの開始/停止
・データソースからのデータの取り出しなど
スキャンした空間データを扱う
データソース
Room Modelとして指定された
スキャンデータを扱うデーソース
実機で空間すデータをスキャンする
インスペクターから設定できる内容
SpatialMapping.prefabにアタッチされているスク
リプト
SpatialMappingObserver.cs
◦ Triangles Per Cubic Meter
1立方メートルあたりに計算するポリゴン数。
◦ Time Between Updates
スキャンの更新間隔時間(単位は秒)
◦ Observer Volume Type
空間領域の形状と向き
◦ Axis Aligned Box: Worldアンカーと同じ軸の箱
◦ Oriented Box: 傾きを指定できる(Orientationで指定)
◦ Sphere: 球体
◦ Extents
空間領域の大きさ(単位はm)
◦ Origin
空間領域の開始位置
(C) 2018 石井 勇一 102
インスペクターから設定できる内容
SpatialMapping.prefabには3つのスクリプトが
アタッチされています。
SpatialMappingManager
◦ Physics Layer
生成したメッシュのGameObjectのレイヤー番号
◦ Surface Material
メッシュに割り当てるマテリアル
◦ Auto Start Observer
空間スキャンを自動的に始めるかどうか
◦ Draw Visual Meshes
メッシュの描画を行うかどうか
◦ Cast Shadow
メッシュに影を表示するか
(C) 2018 石井 勇一 103
インスペクターから設定できる内容
SpatialMapping.prefabには3つのスクリプトが
アタッチされています。
ObjectSurfaceObserver
◦ Room Model
予めスキャン済みの部屋のモデルをプレハブを
指定する
◦ Simulated Update Period In Seconds
シミュレートするアップデート間隔(単位は秒)。
ゼロ以上の場合、サーフェスオブジェクトはこの
期間に更新される場合に使用します。 これは、
Spatial Understandingライブラリなどのように更
新に応答するライブラリを使用する際に便利で
す。負の場合、サーフェスは更新されません。
(C) 2018 石井 勇一 104
その他追加情報
HoloToolkitのSpatialMappingを理解する by D.YAMA Blog 
◦ http://blog.d‐yama7.com/archives/708
ここに各クラスのメソッドや利用例などが書かれています。
(C) 2018 石井 勇一 105
1.5 UX Controls
(C) 2018 石井 勇一 106
HoloLens用UI部品とサンプル
現在のバージョンで試せるデモがExampleに入っています。
(C) 2018 石井 勇一 107
UI部品
テキスト系とボタン系、その他に分かれています。
テキスト系
◦ 3DTextPrefab
3D Text Meshを使用している。
◦ UITextPrefab
uGUIを使用。このプレハブのトップはCanvasなので注意。
(C) 2018 石井 勇一 108
UI部品
ボタン系
動作確認は InteractableObjectExamples.unity
(C) 2018 石井 勇一 109
UI部品
ボタン系は「CompoundButtonスクリプト」を用いてインタラクティブな反応をするように設計さ
れています。
このスクリプトを利用することで、HoloLensのジェスチャ入力に対して、任意のオブジェクトをイ
ンタラクティブなボタンにすることができます。
「インタラクティブオブジェクト」に関する詳細はこちらを参照
https://developer.microsoft.com/en‐us/windows/mixed‐reality/interactable_object
(C) 2018 石井 勇一 110
UI部品
ボタンの状態
◦ Observation: デフォルトのアイドル状態
◦ Targeted:オブジェクトが注視カーソルでターゲットに設定されているとき。
◦ Pressed:エアタップジェスチャーでオブジェクトをクリックしたとき
(C) 2018 石井 勇一 111
Compound Buttonクラス
これはボタンコンポーネントのベースとなるクラス。
(C) 2018 石井 勇一 112
Compound Button Meshクラス
カスタムメッシュやそれぞれの状態に応じた色やスケールなどをまとめて管理する
(C) 2018 石井 勇一 113
Compound Button Iconクラス
ボタンのアイコンを管理するクラス
(C) 2018 石井 勇一 114
Compound Button Iconクラス
アイコンの割り当ての手順
(C) 2018 石井 勇一 115
Compound Button Textクラス
TextMeshコンポーネントによりボタンにテキ
ストを表示する。
このスクリプトをCompoundButtonSpeechコン
ポーネントと組み合わせて使用すると、ボタン
をスピーチ入力のキーワードに自動的にリン
クできます。
(C) 2018 石井 勇一 116
Compound Button Soundクラス
様々なボタンの状態に合わせたサウンドを
設定できます。
(C) 2018 石井 勇一 117
Compound Button Animクラス
ボタンコンポーネントのベースクラス。実装サンプル例はButtonCheeseを参照
(C) 2018 石井 勇一 118
Compound Button Speechクラス
このスクリプトを使用して、Speech Manager
にボタン用のキーワードを自動的に登録しま
す(このスクリプトはテスト済みではあります
が、まだ実験的機能となっています) 。
この機能を利用するにはUWP Capabilityの
設定が必要です。
(C) 2018 石井 勇一 119
Compound Button Toggleクラス
このスクリプトを使用して、トグルのオン/オフ状態を追加します(現時点では使用例が見当た
らない)
(C) 2018 石井 勇一 120
イベントの受信方法
InteractionReceiverの派生クラスを作成する
と、複数のボタンイベントをまとめて管理する
ことができます。
実装例はExamplesのUX/Scriptsにある
ButtonReceiverExampleです。
(C) 2018 石井 勇一 121
InteractionReceiverでオーバーライド可
能メソッド
(C) 2018 石井 勇一 122
#region Protected Virtual Callback Functions
protected virtual void FocusEnter(GameObject obj, PointerSpecificEventData eventData) { }
protected virtual void FocusExit(GameObject obj, PointerSpecificEventData eventData) { }
protected virtual void InputDown(GameObject obj, InputEventData eventData) { }
protected virtual void InputUp(GameObject obj, InputEventData eventData) { }
protected virtual void InputClicked(GameObject obj, InputClickedEventData eventData) { }
protected virtual void HoldStarted(GameObject obj, HoldEventData eventData) { }
protected virtual void HoldCompleted(GameObject obj, HoldEventData eventData) { }
protected virtual void HoldCanceled(GameObject obj, HoldEventData eventData) { }
protected virtual void ManipulationStarted(GameObject obj, ManipulationEventData eventData) { }
protected virtual void ManipulationUpdated(GameObject obj, ManipulationEventData eventData) { }
protected virtual void ManipulationCompleted(GameObject obj, ManipulationEventData eventData) { }
protected virtual void ManipulationCanceled(GameObject obj, ManipulationEventData eventData) { }
protected virtual void NavigationStarted(GameObject obj, NavigationEventData eventData) { }
protected virtual void NavigationUpdated(GameObject obj, NavigationEventData eventData) { }
protected virtual void NavigationCompleted(GameObject obj, NavigationEventData eventData) { }
protected virtual void NavigationCanceled(GameObject obj, NavigationEventData eventData) { }
#endregion
ButtonReceiverExampleのコード
(C) 2018 石井 勇一 123
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity.Receivers;
using HoloToolkit.Unity.InputModule;
namespace HoloToolkit.Unity.Examples
{
public class ButtonReceiverExample : InteractionReceiver
{
public GameObject textObjectState;
private TextMesh txt;
void Start()
{
txt = textObjectState.GetComponentInChildren<TextMesh>();
}
ButtonReceiverExampleのコード
(C) 2018 石井 勇一 124
protected override void FocusEnter(GameObject obj, PointerSpecificEventData eventData) {
Debug.Log(obj.name + " : FocusEnter");
txt.text = obj.name + " : FocusEnter";
}
protected override void FocusExit(GameObject obj, PointerSpecificEventData eventData) {
Debug.Log(obj.name + " : FocusExit");
txt.text = obj.name + " : FocusExit";
}
protected override void InputDown(GameObject obj, InputEventData eventData) {
Debug.Log(obj.name + " : InputDown");
txt.text = obj.name + " : InputDown";
}
protected override void InputUp(GameObject obj, InputEventData eventData) {
Debug.Log(obj.name + " : InputUp");
txt.text = obj.name + " : InputUp";
}
}
}
その他の実装例
ExampleのUX/Scriptsを参照
(C) 2018 石井 勇一 125
Interactive
IInputClickHandler
IFocusable
IInputHandler
InteractiveButton InteractiveToggle
InteractiveToggleButton
Exampleカスタムボタン
Holographic button
全てのボタンはHoloToolkit‐Examples/UX/Prefabの下にあります。
(C) 2018 石井 勇一 126
Exampleカスタムボタン
Mesh button
(C) 2018 石井 勇一 127
Exampleカスタムボタン
Traditional button
(C) 2018 石井 勇一 128
Exampleカスタムボタン
Other examples
この他にも幾つかのアニメーション付き3D Meshボタンがあります。
(C) 2018 石井 勇一 129
1.6 Spatial Understanding
(C) 2018 石井 勇一 130
空間の平面を把握
Spatial Mappingにより空間の把握ができるようになりましたが、実際に物を配置するときには
それが「壁」「床」「天井」と認識する必要があります。
Spatial Understandingは、Fragmentsの開発中に空間把握の必要性に直面し開発されました。
https://www.microsoft.com/ja‐jp/hololens/apps/fragments
ここで開発されたライブラリはカプセル化されて、MRTKで利用できるようになっています。
(C) 2018 石井 勇一 131
サンプルを動作させる
Assets/HoloToolkit‐Examples/SpatialUnderstanding/Scenes/SpatialUnderstandingExampleを開く
Spatial Mappingと同様にSpatial Perceptionの設定が必要です。
実行はHoloLens Emulation無し、あるいは実機で動作させてください。実行はHoloLens 
Emulation無しの場合は、ダミールームを設定してください。
ある程度認識しないとメニューが出ません。部屋の中をうろうろして平面をたくさん見つけてくだ
さい(床、壁、テーブル、椅子、天井など)
(C) 2018 石井 勇一 132
サンプルを動作させる
上手くある程度以上の平面を検出できるとAirTapして完了というメッセージ(英語)がでるので、
AirTapします。するとメニューが表示されます。
(C) 2018 石井 勇一 133
サンプルを動作させる
Topology Queries(位置の問い合わせ)
◦ Positions on wall 
オブジェクトを配置できる壁の場所を教えてくれます。
◦ Large positions on wall
スペースが大きい壁の位置を示します。
◦ Largest wall
認識した壁の中で一番大きい壁を教えてくれます。
◦ Positions on floor
床にオブジェクトを配置します。
◦ Large positions on floor
スペースが大きい床の位置を教えてくれます。
◦ Place objects positions
オブジェクトを配置できる場所を示します。
(C) 2018 石井 勇一 134
サンプルを動作させる
Shape Queries(形状の問い合わせ)
◦ All surfaces
認識した全ての平面を示します。
◦ Sittable
座ることが可能な場所を教えてくれます。
◦ Chair
認識した椅子を示してくれます。
◦ Large surfaces 
スペースの大きい平面を教えてくれます。
◦ Large empty surfaces 
障害物などがない大きな平面を示します。
◦ Couch
ソファーの場所を教えてくれます。
(C) 2018 石井 勇一 135
サンプルを動作させる
Object Placement(物を配置する)
◦ On Floor
床に物を配置する
◦ On Wall
壁に物を配置する
On Celling
天井に物を配置する
◦ On SurfaceEdge
狭い平面上に物を配置する
◦ On FloorAndCelling
床と天井に合わせて物を配置する
◦ RandomInAirAwayFromMe
自分から離れた空中にランダムに物を配置する
◦ OnEdge NearCenter
中心近くの端に物を配置する
◦ OnFloor AwayFromMe
自分から離れた床に物を配置する
◦ OnFloor NearMe
自分の近くの床に物を配置する
(C) 2018 石井 勇一 136
Spatial Understanding関連スクリプト
SpatialUnderstanding.cs
◦ スキャンプロセスの状態とフローを制御します。
SpatialUnderstandingCustomMesh.cs
◦ Understanding dllによって生成されたカスタムメッシュを処理します。
◦ メッシュはスキャンフェーズ中に生成され、スキャンファイナライズにもう一度生成されます。
◦ メッシュを使用して、スキャンの進行状況を視覚化することができます。
SpatialUnderstandingDll.cs
◦ マーシャリングヘルパ関数を含む主要なDLLの関数をカプセル化します。
◦ DLL関数は以下の4つに分かれています。
◦ 自分自身
◦ SpatialUnderstandingDllTopology
◦ SpatialUnderstandingDllShapes
◦ SpatialUnderstandingDllObjectPlacement
◦ このクラスには、スキャンフロー、レイキャスト、および整列関数が含まれています。
(C) 2018 石井 勇一 137
Spatial Understanding関連スクリプト
SpatialUnderstandingDllObjectPlacement.cs
◦ understanding dllのオブジェクト配置クエリをカプセル化します。 これらのクエリは、スキャンが完了するまで
有効ではありません。
SpatialUnderstandingDllShapes.cs
◦ understanding  dllの形状検出クエリをカプセル化します。 図形はAddShapeでユーザーによって定義され、分
析はActivateShapeAnalysisで開始されます。 これらのクエリは、スキャンが完了するまで有効ではありません。
形状定義は、コンポーネントのリストと、コンポーネント間の要件を定義する形状制約のリストで構成されま
す。 各コンポーネントは、独自の形状コンポーネント制約のリストによって定義されます。
SpatialUnderstandingDllTopology.cs
◦ understanding  dllのトポロジクエリをカプセル化します。 これらのクエリは、スキャンが完了するまで有効では
ありません。
SpatialUnderstandingSourceMesh.cs
◦ 入力メッシュをSpatial UnderstandingのDLLに提供します。 コンポーネントは、空間マッピングモジュールに依
存します。 空間マッピングのSurfaceObjectリストから更新された必要なdll形式のメッシュリストを保持します。
(C) 2018 石井 勇一 138
サンプルシーン
SpatialUnderstandingExample
(C) 2018 石井 勇一 139
SpatialMappingおよび
SpatialUnderstandingプレハブが必要
サンプルシーンのメインプログラム
Spatial Understandingの設定
Spatial Understanding コンポーネント
◦ Update Period_During Scanning
◦ スキャン処理中に使用される更新期間(通常、スキャンが完
了した後よりも高速)(単位不明)
◦ Update Period_After Scanning
◦ スキャン処理が完了した後に使用される更新期間(単位不明)
(C) 2018 石井 勇一 140
Spatial Understandingの設定
Spatial Understanding Custom Meshコンポー
ネント
◦ Import Mesh Period
◦ スキャンフェーズ中に、メッシュをインポートする間隔を秒
単位で指定します。 0の値は、DLLからメッシュのインポート
を行いません。
◦ Mesh Material
◦ DLLによって生成されたカスタムメッシュをレンダリングする
ために使用されるマテリアル。
◦ Max Frame Time
◦ メッシュの処理に費やすフレームあたりの最大時間(ミリ
秒)。処理が1フレームに割り当てられている時間を超過し
ないようにするために使用されます。
◦ Create Mesh Colliders
◦ Meshコライダーを生成するかどうか。
(C) 2018 石井 勇一 141
サンプルプログラムの流れ
AppState.csのStartメソッド(以下、すべてAppState.cs内のメソッド)
(C) 2018 石井 勇一 142
namespace HoloToolkit.Examples.SpatialUnderstandingFeatureOverview
{
public class AppState : Singleton<AppState>, ISourceStateHandler, IInputClickHandler
{
private void Start()
{
// Default the scene & the HoloToolkit objects to the camera
Vector3 sceneOrigin = CameraCache.Main.transform.position;
Parent_Scene.transform.position = sceneOrigin;
MappingObserver.SetObserverOrigin(sceneOrigin);
InputManager.Instance.AddGlobalListener(gameObject);
var keywordsToActions = new Dictionary<string, Action>
{
{ "Toggle Scanned Mesh", ToggleScannedMesh },
{ "Toggle Processed Mesh", ToggleProcessedMesh },
};
keywordRecognizer = new KeywordRecognizer(keywordsToActions.Keys.ToArray());
keywordRecognizer.OnPhraseRecognized += args => keywordsToActions[args.text].Invoke();
keywordRecognizer.Start();
}
音声入力
どこでも
ハンドジェスチャー
入力
サンプルプログラムの流れ
必要なところだけ抜粋(AppState.cs)
(C) 2018 石井 勇一 143
protected override void OnDestroy()
{
InputManager.Instance.RemoveGlobalListener(gameObject);
}
Start()で登録した
どこでもハンドジェス
チャー入力を削除
ハンドジェスチャー入力
ISourceStateHandler(手の検出), IInputClickHandler(AirTapの検出)
(C) 2018 石井 勇一 144
public void OnSourceDetected(SourceStateEventData eventData) {
// If the source has positional info and there is currently no visible source
if (eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.Position))
{
trackedHandsCount++;
}
}
public void OnSourceLost(SourceStateEventData eventData) {
if (eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.Position))
{
trackedHandsCount--;
}
}
public void OnInputClicked(InputClickedEventData eventData) {
if ((SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Scanning) &&
!SpatialUnderstanding.Instance.ScanStatsReportStillWorking)
{
SpatialUnderstanding.Instance.RequestFinishScan();
}
}
指を検出したタイミングで
メッセージの色を変えるた
めにカウントを記録
十分なデータがえらたタイ
ミングで、AirTapで終了依
頼を発行するために使用
音声入力
Spatial MappingのVisual MeshとSpatial UnderstandingのCustomMeshをそれぞれOn/Offする
実はキーボード入力でも最終的にここが呼ばれるようにプログラムされている(後述)
(C) 2018 石井 勇一 145
private static void ToggleScannedMesh()
{
SpatialMappingManager.Instance.DrawVisualMeshes = !SpatialMappingManager.Instance.DrawVisualMeshes;
Debug.Log("SpatialUnderstanding -> SpatialMappingManager.Instance.DrawVisualMeshes=" +
SpatialMappingManager.Instance.DrawVisualMeshes);
}
private static void ToggleProcessedMesh()
{
SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh =
!SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh;
Debug.Log("SpatialUnderstanding -> SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh=" +
SpatialUnderstanding.Instance.UnderstandingCustomMesh.DrawProcessedMesh);
}
Updateメソッド
Spatial Understandingのステータスに合わせてメッセージを変える、キーボードの入力を監視
する処理を呼び出している
(C) 2018 石井 勇一 146
private void Update()
{
Update_DebugDisplay(Time.deltaTime);
Update_KeyboardInput(Time.deltaTime);
}
Update_DebugDisplayメソッド
DebugDisplayおよびDebugSubDisplayには3D 
Text Meshコンポーネントがセットされています。
(C) 2018 石井 勇一 147
private void Update_DebugDisplay(float deltaTime)
{
// Basic checks
if (DebugDisplay == null)
{
return;
}
// Update display text
DebugDisplay.text = PrimaryText;
DebugDisplay.color = PrimaryColor;
DebugSubDisplay.text = DetailsText;
}
3つのプロパティについて
PrimaryText、PrimaryColor、DetailsTextはすべて読み取り専用のプロパティとして定義されています。
それぞれの役割は以下のようになっています。
PrimaryText
◦ 現在のステータスに合わせてメインメッセージを表示(ユーザへの指示にもなっている)
PrimaryColor
◦ ステータスに合わせてメッセージの色を変更。Understanding処理中/終わった、指を検出した/見失ったなど
DetailsText
◦ Understandingで検出した物のサマリを表示。ある程度以上検出しないと表示されない。
(C) 2018 石井 勇一 148
public string PrimaryText
{
get
{
:
:
スキャンの状態
SpatialUnderstandingクラスで定義されているScanStates
(C) 2018 石井 勇一 149
ReadyToScan
Scanning
Finishing
Done
namespace HoloToolkit.Unity
{
public class SpatialUnderstanding : Singleton<SpatialUnderstanding>
{
// Enums
public enum ScanStates
{
None,
ReadyToScan,
Scanning,
Finishing,
Done
}
}
}
RequestBeginScanningメソッド
または
AutoBeginScanningプロパティがtrue
RequestFinishScanメソッド
(DLL内部処理完了)
PrimaryTextプロパティの処理
ScanStateに合わせてメインメッセージを変更
SpaceVisualizer.cs
◦ SpaceQueryDescriptionを使用
LevelSolver.cs
◦ ObjectPlacementDescriptionを使用
(C) 2018 石井 勇一 150
public string PrimaryText {
get {
// 空間および物の配置のリストに対する検索結果を表示(優先度があります)
if (!string.IsNullOrEmpty(SpaceQueryDescription)) {
return SpaceQueryDescription;
} else if (!string.IsNullOrEmpty(ObjectPlacementDescription)) {
return ObjectPlacementDescription;
}
:
:
【参考】SpaceQueryDescriptionおよび
ObjectPlacementDescriptionプロパティ
SpaceQueryDescriptionおよびObjectPlacementDescriptionプロパティ
何方かの値をsetし、もう一方の値を""にする。
(C) 2018 石井 勇一 151
public string SpaceQueryDescription {
get { return spaceQueryDescription; }
set { spaceQueryDescription = value;
objectPlacementDescription = "";
}
}
public string ObjectPlacementDescription {
get { return objectPlacementDescription; }
set { objectPlacementDescription = value;
spaceQueryDescription = "";
}
}
PrimaryTextプロパティの処理
ScanStateに合わせてメインメッセージを変更(続き)
(C) 2018 石井 勇一 152
// Scan state
if (SpatialUnderstanding.Instance.AllowSpatialUnderstanding){
switch (SpatialUnderstanding.Instance.ScanState) {
case SpatialUnderstanding.ScanStates.Scanning: //スキャン中
// Get the scan stats
IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
if (SpatialUnderstandingDll.Imports.QueryPlayspaceStats(statsPtr) == 0){
return "playspace stats query failed";
}
// 終了させても良さそうかどうか調べる(これも複雑なコードが付いているプロパティ)
if (DoesScanMeetMinBarForCompletion) {
return "When ready, air tap to finalize your playspace"; // AirTapで終了するというメッセージを表示
}
return "Walk around and scan in your playspace"; // まだ不十分なので歩き回ってスキャンしなさいと表示
:
:
PrimaryTextプロパティの処理
ScanStateに合わせてメインメッセージを変更(続き)
(C) 2018 石井 勇一 153
case SpatialUnderstanding.ScanStates.Finishing: // 終了処理中
return "Finalizing scan (please wait)";
case SpatialUnderstanding.ScanStates.Done: // 終了
return "Scan complete - Use the menu to run queries";
default:
return "ScanState = " + SpatialUnderstanding.Instance.ScanState.ToString();
}
}
return "";
}
PrimaryColorプロパティの処理
◦ ステータスに合わせてメッセージの色を変更。
(C) 2018 石井 勇一 154
public Color PrimaryColor {
get {
if (SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Scanning){
if (trackedHandsCount > 0) {
return DoesScanMeetMinBarForCompletion ? Color.green : Color.red;
}
return DoesScanMeetMinBarForCompletion ? Color.yellow : Color.white;
}
// メニューを見ているときはそれを消す(実際には透明度15%にする)
Vector3 hitPos, hitNormal;
UnityEngine.UI.Button hitButton;
float alpha = AppCursor.RayCastUI(out hitPos, out hitNormal, out hitButton) ? 0.15f : 1.0f;
// 特殊ケース処理 &
return (!string.IsNullOrEmpty(SpaceQueryDescription) || !string.IsNullOrEmpty(ObjectPlacementDescription)) ?
(PrimaryText.Contains("processing") ? new Color(1.0f, 0.0f, 0.0f, 1.0f) : new Color(1.0f, 0.7f, 0.1f, alpha)) :
new Color(1.0f, 1.0f, 1.0f, alpha);
}
}
DetailsTextプロパティの処理
◦ 検索結果のサマリー
(C) 2018 石井 勇一 155
public string DetailsText {
get {
if (SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.None)
{
return "";
}
// スキャン統計は2番目に優先されます
if ((SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Scanning) &&
(SpatialUnderstanding.Instance.AllowSpatialUnderstanding))
{
// 統計情報が取得できていない場合は取得に失敗という文字列を返す
IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
if (SpatialUnderstandingDll.Imports.QueryPlayspaceStats(statsPtr) == 0)
{
return "Playspace stats query failed";
}
:
:
PrimaryColorプロパティの処理
◦ ステータスに合わせてメッセージの色を変更。
(C) 2018 石井 勇一 156
SpatialUnderstandingDll.Imports.PlayspaceStats stats =
SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStats();
// 統計情報がゼロでなければ統計情報の表示を開始する
if (stats.TotalSurfaceArea > kMinAreaForStats) {
string subDisplayText = string.Format("totalArea={0:0.0}, horiz={1:0.0}, wall={2:0.0}",
stats.TotalSurfaceArea, stats.HorizSurfaceArea, stats.WallSurfaceArea);
subDisplayText += string.Format("¥nnumFloorCells={0}, numCeilingCells={1}, numPlatformCells={2}",
stats.NumFloor, stats.NumCeiling, stats.NumPlatform);
subDisplayText += string.Format("¥npaintMode={0}, seenCells={1}, notSeen={2}",
stats.CellCount_IsPaintMode,
stats.CellCount_IsSeenQualtiy_Seen + stats.CellCount_IsSeenQualtiy_Good,
stats.CellCount_IsSeenQualtiy_None);
return subDisplayText;
}
return "";
}
return "";
}
PlayspaceStatsクラスの定義は次
のスライドを参照
(C) 2018 石井 勇一 157
namespace HoloToolkit.Unity
{
public class SpatialUnderstandingDll {
public class PlayspaceStats {
public int IsWorkingOnStats; // 0 まだ統計を作成している場合
public float HorizSurfaceArea; // In m2 : 床から-0.15~1mの間にある上向きの全ての水平面
public float TotalSurfaceArea; // In m2 : すべて
public float UpSurfaceArea; // In m2 : 床を含むすべての上向きな水平面
public float DownSurfaceArea; // In m2 : 天井を含むすべて下向きの水平面
public float WallSurfaceArea; // In m2 : 壁だけでない、すべての垂直面
public float VirtualCeilingSurfaceArea; // In m2 : 実質的な天井面の推定数
public float VirtualWallSurfaceArea; // In m2 : 実質的な壁の推定数
public int NumFloor; // 各フロアのリスト数(カウントを含む)
public int NumCeiling; // 各天井のリスト数(カウントを含む)
public int NumWall_XNeg; // 各壁においてX軸マイナス方向を向いている数(カウントを含む)
public int NumWall_XPos; // 各壁においてX軸プラス方向を向いている数(カウントを含む)
public int NumWall_ZNeg; // 各壁においてZ軸マイナス方向を向いている数(カウントを含む)
public int NumWall_ZPos; // 各壁においてZ軸プラス方向を向いている数(カウントを含む)
public int NumPlatform; // 床を含まない水平面の数 (例えばテーブルや椅子など)(カウントを含む)
public int CellCount_IsPaintMode; // ペイントセル数(ペイント数で面積が推測できる)=> 1セルにつき8cm×8cm
public int CellCount_IsSeenQualtiy_None; // 見えないセルの数 => 1セルにつき8cm×8cm
public int CellCount_IsSeenQualtiy_Seen; // 見えるセルの数=> 1セルにつき8cm×8cm
public int CellCount_IsSeenQualtiy_Good; // 良質な見えるセルの数 => 1セルにつき8cm×8cm
};
}
}
DoesScanMeetMinBarForCompletionプ
ロパティ
スキャン完了とするための必要最小限度を満たしているかどうかを判定して結果を返す
(C) 2018 石井 勇一 158
public bool DoesScanMeetMinBarForCompletion {
get {
// 実際にスキャンしているか?
if ((SpatialUnderstanding.Instance.ScanState != SpatialUnderstanding.ScanStates.Scanning) ||
(!SpatialUnderstanding.Instance.AllowSpatialUnderstanding))
{
return false;
}
// 現在の統計情報を調べる
IntPtr statsPtr = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStatsPtr();
if (SpatialUnderstandingDll.Imports.QueryPlayspaceStats(statsPtr) == 0)
{
return false;
}
:
:
DoesScanMeetMinBarForCompletionプ
ロパティ
スキャン完了とするための必要最小限度を満たしているかどうかを判定して結果を返す
(C) 2018 石井 勇一 159
SpatialUnderstandingDll.Imports.PlayspaceStats stats =
SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticPlayspaceStats();
// 事前に設定した値と比較する
if ((stats.TotalSurfaceArea > kMinAreaForComplete) || // トータルの表面領域
(stats.HorizSurfaceArea > kMinHorizAreaForComplete) || // 床から-0.15~1mの間にある上向きの全ての水平面
(stats.WallSurfaceArea > kMinWallAreaForComplete)) // 壁だけでない、すべての垂直面
{
return true;
}
return false;
}
}
// 事前設定
public float kMinAreaForStats = 5.0f;
public float kMinAreaForComplete = 50.0f;
public float kMinHorizAreaForComplete = 25.0f;
public float kMinWallAreaForComplete = 10.0f;
統計情報の利用
UI.csのSetupMenus()
(C) 2018 石井 勇一 160
private void SetupMenus()
{
// Topology queries
ButtonPanels[(int)Panels.Topology].Button.GetComponentInChildren<Text>().text = "Topology Queries";
ButtonPanels[(int)Panels.Topology].Button.onClick.AddListener(() => { SetActiveTab(Panels.Topology); });
AddButton("Position on wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindPositionOnWall();
timeLastQuery = DateTime.MinValue;
});
AddButton("Large positions on wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindLargePositionsOnWalls();
timeLastQuery = DateTime.MinValue;
});
AddButton("Largest wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindLargeWall();
timeLastQuery = DateTime.MinValue;
});
:
:
統計情報の利用
UI.csのSetupMenus()
(C) 2018 石井 勇一 161
private void SetupMenus()
{
// Topology queries
ButtonPanels[(int)Panels.Topology].Button.GetComponentInChildren<Text>().text = "Topology Queries";
ButtonPanels[(int)Panels.Topology].Button.onClick.AddListener(() => { SetActiveTab(Panels.Topology); });
AddButton("Position on wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindPositionOnWall();
timeLastQuery = DateTime.MinValue;
});
AddButton("Large positions on wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindLargePositionsOnWalls();
timeLastQuery = DateTime.MinValue;
});
AddButton("Largest wall", Panels.Topology, () => {
SpaceVisualizer.Instance.Query_Topology_FindLargeWall();
timeLastQuery = DateTime.MinValue;
});
:
:
統計情報の利用
UI.csのSetupMenus()
(C) 2018 石井 勇一 162
// Shape queries
ButtonPanels[(int)Panels.Shapes].Button.GetComponentInChildren<Text>().text = "Shape Queries";
ButtonPanels[(int)Panels.Shapes].Button.onClick.AddListener(() => { SetActiveTab(Panels.Shapes); });
ReadOnlyCollection<string> customShapes = ShapeDefinition.Instance.CustomShapeDefinitions;
for (int i = 0; i < customShapes.Count; ++i)
{
string shapeName = customShapes[i];
AddButton(shapeName, Panels.Shapes, () =>
{
SpaceVisualizer.Instance.Query_Shape_FindShapeHalfDims(shapeName);
timeLastQuery = DateTime.MinValue;
});
}
:
:
統計情報の利用
UI.csのSetupMenus()
(C) 2018 石井 勇一 163
// Level solver
ButtonPanels[(int)Panels.LevelSolver].Button.GetComponentInChildren<Text>().text = "Object Placement";
ButtonPanels[(int)Panels.LevelSolver].Button.onClick.AddListener(() => {
SetActiveTab(Panels.LevelSolver);
timeLastQuery = DateTime.MinValue;
});
AddButton("On Floor", Panels.LevelSolver, () => {
LevelSolver.Instance.Query_OnFloor();
timeLastQuery = DateTime.MinValue;
});
AddButton("On Wall", Panels.LevelSolver, () => {
LevelSolver.Instance.Query_OnWall();
timeLastQuery = DateTime.MinValue;
});
:
:
統計情報の利用
UI.csのSetupMenus()
(C) 2018 石井 勇一 164
public void Query_Topology_FindPositionOnWall() {
ClearGeometry(); // 既に表示しているワイヤーフレームを消す(2回目を想定)
// Spatial Undedrstandingが有効でなければ何もしない
if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding) {
return;
}
// セットアップ
float minHeightOfWallSpace = 0.5f; // 壁とみなす最小の高さ(単位メートル)
float minWidthOfWallSpace = 0.75f; // 壁とみなす最小の幅(単位メートル)
float minHeightAboveFloor = 1.25f; // 壁とみなす床からの高さ(単位メートル)
float minFacingClearance = 1.5f; // 壁の前に求める最小の空き領域(単位メートル)
// 問い合わせ
IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
int locationCount = SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnWalls(
minHeightOfWallSpace, minWidthOfWallSpace, minHeightAboveFloor, minFacingClearance,
resultsTopology.Length, resultsTopologyPtr);
// 出力
HandleResults_Topology("Find Position On Wall", locationCount, new Vector3(minWidthOfWallSpace, minHeightOfWallSpace, 0.025f), Color.blue);
}
統計情報の利用
SpatialUnderstandingDllTopology.csのQueryTopology_FindPositionsOnWalls ()
(C) 2018 石井 勇一 165
/// <summary>
///パラメータで指定された基準を満たす壁のスペースを検索します。
/// </summary>
/// <param name="minHeightOfWallSpace">クエリによって検出されるスペースの最小高さ。</param>
/// <param name="minWidthOfWallSpace">クエリによって検出されるスペースの最小幅。</param>
/// <param name="minHeightAboveFloor">そのスペースの下端と床の上との最小距離。</param>
/// <param name="minFacingClearance">そのスペースの前方のゆとり空間の最小距離。</param>
/// <param name="locationCount">locationDataでユーザーが指定したロケーション結果の数。</param>
/// <param name="locationData">クエリによって検出されたスペースで満たされるTopologyResultのロケーション結果配列。</param>
/// <returns>クエリによって検出されたスペースの数。 この値は、呼び出し元によって提供された結果の数によって制限されます(locationCount)</returns>
// Queries (topology)
[DllImport("SpatialUnderstanding", CallingConvention = CallingConvention.Cdecl)]
public static extern int QueryTopology_FindPositionsOnWalls(
[In] float minHeightOfWallSpace,
[In] float minWidthOfWallSpace,
[In] float minHeightAboveFloor,
[In] float minFacingClearance,
[In] int locationCount, // locationDataに割り当てられた領域を渡します。
[In, Out] IntPtr locationData); // TopologyResult
統計情報の利用
ShapeDefinition.csのCreateCustomShapeDefinitions()にて、想定される形のデータを登録し、
統計情報から登録された形データを元に検索ができる。
「椅子」の定義例
(C) 2018 石井 勇一 166
// Chair
shapeComponents = new List<SpatialUnderstandingDllShapes.ShapeComponent>()
{
new SpatialUnderstandingDllShapes.ShapeComponent(
new List<SpatialUnderstandingDllShapes.ShapeComponentConstraint>()
{
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_SurfaceHeight_Between(0.25f, 0.6f),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_SurfaceCount_Min(1),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_IsRectangle(),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_RectangleLength_Between(0.1f, 0.5f),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_RectangleWidth_Between(0.1f, 0.4f),
SpatialUnderstandingDllShapes.ShapeComponentConstraint.Create_SurfaceNotPartOfShape("Couch"),
}),
};
AddShape("Chair", shapeComponents);
最小限度の設定の例
ZuQ9‐>Nn To 辛周(ズキューンとからまわり)さんのブログ
◦ HoloLens開発 SpatialUnderstanding事始め 空間検知と空間内の情報(天井、床、壁)の判定まで
◦ http://zuq9nn.blogspot.jp/2017/06/hololens‐spatialunderstanding.html
◦ HoloLensの開発 SpatialUnderstandingDllTopologyで壁にオブジェクト配置してみる
◦ http://zuq9nn.blogspot.jp/2017/09/hololensspatialunderstandingdlltopology.html
(C) 2018 石井 勇一 167
1.7 Sharing
(C) 2018 石井 勇一 168
Sharingとは
2台以上のHoloLensで空間を共有する仕組み
(C) 2018 石井 勇一 169
全く異なるリアル空間で同じものを見る
たまたま同じリアル空間で同じものを見る
接続形態
MixedRealityToolkitに含まれるSharing機能を使う
◦ サーバは独立したPCで実行
UNETやPhotonといったネットワーキングエンジンを使う
◦ UNET版はサンプルがあります。
TCP/UDPで独自に実装する
◦ 自由度が高いが、難易度も高い。多くの実装例がネットを探すと出てきます。
(C) 2018 石井 勇一 170
Sharingとは
Sharingを実現するには2台以上のHoloLensとサーバが必要
(C) 2018 石井 勇一 171
Sharingサーバ
(独立したPC)
HoloLens HoloLens
Sharingとは
Sharingを実現するには2台以上のHoloLensとサーバが必要
(C) 2018 石井 勇一 172
Sharingサーバ
(HoloLens)
HoloLens
HoloLens
ある一台のHoloLensをサーバ兼クライアントにする
UNET版
Sharing時の問題点
HoloLensアプリは起動時にカメラの位置がPosition(0, 0, 0)、Rotation(0,0,0)になります。これが
基準点となり作られた座標系を「静止座標系(Stationary frame of reference)と言います。
そのため図のよう起動するとそれぞれ異なる静止座標系が構築されます。
(C) 2018 石井 勇一 173
Sharing時の問題点
そこで、それぞれの座標系に「アンカー」を共有し、それ以降はアンカーを基準に全ての物を
共有することで問題点を解決します。
これをSpatial anchor(空間アンカー)と呼びます。
実際にプログラムするときは「World Anchor」と呼ばれるクラスを使用します。
(C) 2018 石井 勇一 174
World Anchorについて
World Anchorになりそうなもの
◦ 起動時の位置
◦ 画像認識(VuforiaやOpenCVなどと組み合わせて同じ特徴を持つ画像を元に位置合わせをする)
(C) 2018 石井 勇一 175
サンプルプログラムを実行
2つのフォルダーに分かれています
(C) 2018 石井 勇一 176
独自サーバプログラムを使用
するバージョン
UNETを使用するバージョン。
最初に起動したHoloLensアプリが
サーバになる。
独自サーバ版の利用方法
https://github.com/Microsoft/MixedRealityTo
olkit‐Unity/releases
で配布されているMixedRealityToolkit‐Unity‐
2017.2.1.3.zipを取得し展開する
(C) 2018 石井 勇一 177
独自サーバ版の利用方法
MixedRealityToolkit‐Unity‐2017.2.1.3.zipの展開後のExternalフォルダをUnityで使用しているプ
ロジェクトのトップディレクトリにコピーする
(C) 2018 石井 勇一 178
Unityプロジェクト
zipファイルの中にある
Externalフォルダ
コピーする
独自サーバ版の利用方法
Unityの[Mixed Reality Toolkit]‐[Sharing Service]‐[Launch Sharing Service]を実行
(C) 2018 石井 勇一 179
独自サーバ版の利用方法
コマンドプロンプトが表示される。初回起動時はネットワークの許可を求めるダイアログが表
示される。
表示されているIPアドレスを覚える。
一般的には一番上のアドレスを使用する。
(C) 2018 石井 勇一 180
独自サーバ版の利用方法
Unityの[Mixed Reality Toolkit]‐[Configure]‐[Apply UWP Capability Settings]を実行
(C) 2018 石井 勇一 181
独自サーバ版の利用方法
必須
◦ Internet Client Server
◦ Private Network Client Server
今回のサンプルにおいて必要
◦ Spatial Perception(UNET版で使用)
(C) 2018 石井 勇一 182
独自サーバ版の利用方法
SharingTestを開く
[File]‐[Build & Settings]にてSharingTestを一番最初に起動するシーンに設定し、[Build]を実行
(C) 2018 石井 勇一 183
独自サーバ版の利用方法
HoloLensにて、サーバのIPアドレスを入力し、
[Connect]ボタンを押す
上手くつながると中央左の赤い丸が緑に変
わる。
さらに後ろのメッセージにおいて、
WolrdAnchorを記録したというメッセージも表
示される。
またサーバー側のコマンドプロントにもクライ
アントからの接続を表すメッセージが表示され
る。
これを複数台のHoloLensから行う
(C) 2018 石井 勇一 184
UNET版によるSharing
Unityの[Mixed Reality Toolkit]‐[Configure]‐[Apply UWP Capability Settings]は同じ
(C) 2018 石井 勇一 185
UNET版によるSharing
SharingWithUnetExampleを開き、[File]‐[Build & Settings]にてSharingTestを一番最初に起動す
るシーンに設定し、[Build]を実行
(C) 2018 石井 勇一 186
UNET版によるSharing
初回起動時は、左下の「Startボタン」をAirTapする
2台目以降のHoloLensにおいては1台目のHoloLensがリストに表示されるのでそれを選択して
から、右下の「Join」ボタンをAirTap。
これで空間共有がうまくいくと、お互いにAirTapで弾を撃ちあえます。
(C) 2018 石井 勇一 187
Sharingに関する情報
お手軽にSharingの接続成功率と精度をあげる by d_yama
◦ http://blog.d‐yama7.com/archives/569
HoloToolkit‐UnityのSharingの仕組みをできるだけ簡単に理解する by @miyaura
◦ https://qiita.com/miyaura/items/da1d7bd253c3299327ba
HoloLensの空間共有サービスを使ってみよう byフューチャーアーキテクト開発者ブログ
◦ https://future‐architect.github.io/articles/20170405/
HoloLensでSharingする前に確認したほうがいいこと by えむにわリソース
◦ http://m2wasabi.hatenablog.com/entry/2017/11/27/202300
(C) 2018 石井 勇一 188
UNETによる接続例
MRが楽しい by bluebirdofozさん
◦ SharingWithUNETについてまとめる その1(その7まであります)
◦ http://bluebirdofoz.hatenablog.com/entry/2018/01/03/225437
(C) 2018 石井 勇一 189
1.8その他便利な機能や
情報
(C) 2018 石井 勇一 190
知っていると便利な機能やスクリプト
DebugEventLog
◦ Consoleメッセージを表示(Unity Editorからリモート実行す
るときに便利かも)
DebugPanelButton
◦ DebugEventLogプレハブの代わりにこちらを配置。実行時
にConsoleメッセージの表示/非表示ができるボタンが表
示される
FPSDisplay
◦ fpsを表示(かなり字が小さいので注意)
HeadsUpDirectionIndicator
◦ アタッチされているスクリプトのTargetに対象の
GameObjectをセットするとその方向を常に表示する矢印
が表示される。ただし1つのゲームオブジェクトにしか使え
ない(ネットを探すと様々な改良を加えている人たちがい
ます)。
HeadsUpDirectionIndicatorPointer
◦ 上のプレハブから呼び出される矢印。直接は利用しない。
(C) 2018 石井 勇一 191
知っていると便利な機能やスクリプト
ホーム画面の様な動きをするスクリプト(Body‐Lock)
◦ Tagalong.cs、 SimpleTagalong.cs、 SphereBasedTagalong.cs (どれか一つ)
常にこちらを向くスクリプト
◦ Billboard.cs
この二つのスクリプトを適当なGameObjectにアタッチする(例えばワールドスペースのCanvas)
パラメーターが沢山あるので自分好みに調整する
改良版
◦ HoloLens 用の Body‐Locked な UI を作ってみた by 凹みTips
◦ http://tips.hecomi.com/entry/2017/04/01/171121
(C) 2018 石井 勇一 192
ユーザのヘッドセットの調整支援
ユーザーがヘッドセットを調整して、デモのシナリオで十分な経験を得ることができます。
アプリをデモする際には、ユーザーがヘッドセットを正しく装着していることを確認することが重
要です。
このシーンでは、ユーザーの視野の端に境界線が表示され、4つの境界線がすべて表示され
るまでヘッドセットを調整するよう指示されます。ユーザー(またはデモンストレーター)は、
AirTapまたは「I'm ready」と言って、実際の体験に進むことができます。
このシーンは、体験を開始する準備が整うと、ユーザーに見える最初のシーンになるように設
計されています。ユーザーは準備ができたら、シーケンスの次のシーンまたは
HeadsetAdjustmentスクリプトのNextSceneNameプロパティで指定されたシーンを読み込みます。
ですが、どうもHoloToolkit‐Unity‐2017.2.1.3はバグってうまく動かなくなっている模様(いくつか
古いMRTKでは動作するらしい)。
(C) 2018 石井 勇一 193
2つのSingletonパターンについて
Mixed Reality Toolkit ‐ Unityが提供するSingletonパターンに使える機能について by @miyaura
https://qiita.com/miyaura/items/d1c23b988e77e6e491f3
(C) 2018 石井 勇一 194
お問い合わせ
株式会社シーディングソフテック 石井 勇一
◦ E‐mail: yuichi.ishii@seedingsoftech.jp
◦ Home Page: http://seedingsoftech.jp/
個人的なお問い合わせ
◦ Twitter: @z_zabaglione
◦ Home Page: http://zabaglione.info/
本資料をシーディングソフテックの書面による事前許可なく本資料を複製、再製、改変、発表、アッ
プロード、掲示、転送、配布することを禁じます。
著者が作成したオリジナルのプログラムコードは個人・商用利用ともに一切の制限もなくロイヤリ
ティフリーでご利用可能です。
画像、音声、3Dモデルデータなどのリソース類、その他のツールやプログラムなどは原著者の利用
許諾に従ってご利用ください。
(C) 2018 石井 勇一 195

UnityによるHoloLensアプリケーション入門