HoloLens (第 1 世代) の基本 101E - エミュレーターを使用した完全なプロジェクト
重要
Mixed Reality Academy のチュートリアルは、HoloLens (第 1 世代)、Unity 2017、Mixed Reality イマーシブ ヘッドセットを考慮して設計されています。 そのため、それらのデバイスの開発に関するガイダンスを引き続き探している開発者のために、これらのチュートリアルをそのまま残しておくことが重要だと考えています。 これらのチュートリアルは、HoloLens 2 に使用される最新のツールセットや対話式操作を反映して更新されることは "ありません"。また、最新バージョンの Unity には対応していない可能性があります。 これらは、サポートされているデバイス上で継続して動作するように、保守されます。 HoloLens 2 向けには、新しいチュートリアル シリーズが投稿されています。
このチュートリアルでは、Unity でビルドされた完全なプロジェクトについて説明します。これは、視線入力、ジェスチャ、音声入力、立体音響、空間マッピングなど、HoloLens の主要な Windows Mixed Reality 機能を示します。 このチュートリアルの所要時間は約 1 時間です。
デバイス サポート
コース | HoloLens | イマーシブ ヘッドセット |
---|---|---|
MR の基本 101E:エミュレーターを使用した完全なプロジェクト | ✔️ |
開始する前に
前提条件
- 適切なツールがインストールされている構成済みの Windows 10 PC。
プロジェクト ファイル
- プロジェクトに必要なファイルをダウンロードします。 Unity 2017.2 以降が必要です。
- デスクトップなどのアクセスしやすい場所にファイルをアーカイブ解除します。 フォルダー名は、Origami のままにしておきます。
Note
ダウンロードする前にソース コードを確認する場合は、GitHub で参照できます。
第 1 章 - "ホログラム" の世界
この章では、最初の Unity プロジェクトをセットアップし、ビルドと配置のプロセスについて順を追って説明します。
目標
- Unity をホログラフィック開発用に設定する。
- ホログラムを作成する。
- 作成したホログラムを確認する。
Instructions
- Unity を起動します。
- [Open] を選択します。
- 先ほどアーカイブ解除した Origami フォルダーの場所を入力します。
- [Origami] を選択し、[フォルダーの選択] をクリックします。
- 新しいシーンを保存します ([File] (ファイル) / [Save Scene As] (名前を付けてシーンを保存))。
- シーンに Origami という名前を付け、[Save] (保存) ボタンを押します。
メイン カメラを設定する
- [Hierarchy](階層) パネルで、 [Main Camera](メイン カメラ) を選択します。
- [インスペクター] で、変換位置を [0]、[0]、[0] に設定します。
- [フラグのクリア] プロパティを見つけ、ドロップダウンを [スカイボックス] から [単色] に変更します。
- [Background](背景) フィールドをクリックして、カラー ピッカーを開きます。
- R、G、B、A を 0 に設定します。
シーンをセットアップする
- [階層] パネルで、[作成]、[空の作成] の順にクリックします。
- 新しい GameObject を右クリックし、[名前の変更] を選択します。 名前 GameObject を OrigamiCollection に変更します。
- [プロジェクト] パネルの [Holograms] フォルダーで、次の操作を行います。
- Stage を [階層] にドラッグして、OrigamiCollection の子にします。
- Sphere1 を [階層] にドラッグして、OrigamiCollection の子にします。
- Sphere2 を [階層] にドラッグして、OrigamiCollection の子にします。
- [階層] パネルで Directional Light オブジェクトを右クリックし、[削除] を選択します。
- [Holograms] フォルダーから、 [階層] パネルのルートに Lights をドラッグします。
- [階層] で OrigamiCollection を選択します。
- [インスペクター] で、変換位置を [0]、[-0.5]、[2.0] に設定します。
- Unity の [再生] ボタンをクリックしてホログラムをプレビューします。
- プレビュー ウィンドウに Origami オブジェクトが表示されます。
- もう一度 [再生] を押すと、プレビュー モードが停止します。
Unity から Visual Studio にプロジェクトをエクスポートする
- Unity で、[File] (ファイル) > [Build Settings] (ビルド設定) の順に選択します。
- [Platform] (プラットフォーム) の一覧で [Windows Store] を選択し、[Switch Platform] (プラットフォームの切り替え) をクリックします。
- [SDK] を [Universal 10] に、[Build Type] (ビルドの種類) を [D3D] に設定します。
- [Unity C# プロジェクト] をオンにします。
- [Add Open Scenes] (開いているシーンを追加) をクリックしてシーンを追加します。
- [Player Settings...] (プレーヤーの設定...) をクリックします。
- [Inspector] (インスペクター) パネルで、Windows Store のロゴ を選択します。 次に、[Publishing Settings] (公開設定) を選択します。
- [Capabilities] (機能) セクションで、[Microphone] (マイク) 機能と [SpatialPerception] 機能を選択します。
- [Build Settings] (ビルド設定) ウィンドウに戻り、[Build] (ビルド) をクリックします。
- "App" という名前の新しいフォルダーを作成します。
- [App] フォルダーを 1 回クリックします。
- [フォルダーの選択] をクリックします。
- Unity での作業が終了すると、エクスプローラー ウィンドウが表示されます。
- [App] フォルダーを開きます。
- Origami Visual Studio ソリューションを開きます。
- Visual Studio の上部のツールバーを使用して、ターゲットを [デバッグ] から [リリース] に、[ARM] から [X86] に変更します。
- [デバイス] ボタンの横にある矢印をクリックし、[HoloLens エミュレーター] を選択します。
- [デバッグ] > [デバッグなしで開始] の順にクリックするか、Ctrl + F5 キーを押します。
- しばらくすると、エミュレーターが起動し、Origami プロジェクトが開始されます。 エミュレーターを初めて起動する場合、エミュレーターが起動するまでに 15 分程度かかる場合があります。 起動したら、閉じないでください。
第 2 章 - 視線入力
この章では、ホログラムを操作する 3 つの方法のうち、最初の方法 (視線入力) を説明します。
目標
- ワールドロックされたカーソルを使用して視線入力を視覚化する。
Instructions
- Unity プロジェクトに戻り、[ビルド設定] ウィンドウがまだ開いている場合は、それを閉じます。
- [プロジェクト] パネルで [Holograms] フォルダーを選択します。
- Cursor オブジェクトを [階層] パネルのルート レベルにドラッグします。
- Cursor オブジェクトをダブルクリックして、詳しく調べます。
- [プロジェクト] パネルで [Scripts] フォルダーを右クリックします。
- [作成] サブメニューをクリックします。
- [C# スクリプト] を選択します。
- スクリプトに WorldCursor という名前を付けます。 注: 名前では、大文字と小文字が区別されます。 拡張子 .cs を追加する必要はありません。
- [階層] パネルで Cursor オブジェクトを選択します。
- WorldCursor スクリプトをドラッグして [インスペクター] パネルにドロップします。
- WorldCursor スクリプトをダブルクリックして Visual Studio で開きます。
- 次のコードをコピーして WorldCursor.cs に貼り付け、[すべて保存] をクリックします。
using UnityEngine;
public class WorldCursor : MonoBehaviour
{
private MeshRenderer meshRenderer;
// Use this for initialization
void Start()
{
// Grab the mesh renderer that's on the same object as this script.
meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>();
}
// Update is called once per frame
void Update()
{
// Do a raycast into the world based on the user's
// head position and orientation.
var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;
RaycastHit hitInfo;
if (Physics.Raycast(headPosition, gazeDirection, out hitInfo))
{
// If the raycast hit a hologram...
// Display the cursor mesh.
meshRenderer.enabled = true;
// Move thecursor to the point where the raycast hit.
this.transform.position = hitInfo.point;
// Rotate the cursor to hug the surface of the hologram.
this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
}
else
{
// If the raycast did not hit a hologram, hide the cursor mesh.
meshRenderer.enabled = false;
}
}
}
- [ファイル] > [ビルド設定] の順に選択して、アプリをリビルドします。
- 先ほどエミュレーターへの配置に使用した Visual Studio ソリューションに戻ります。
- メッセージが表示されたら、[再読み込み] を選択します。
- [デバッグ] > [デバッグなしで開始] の順にクリックするか、Ctrl + F5 キーを押します。
- Xbox コントローラーを使用してシーンを見回します。 カーソルの動きが物体の形状にどのように関係するかがわかります。
第 3 章 - ジェスチャ
この章では、ジェスチャのサポートを追加します。 Unity の物理エンジンを使って重力を有効にし、紙で作った球体をユーザーが選択すると、その球体が落下するようにします。
目標
- "Select" ジェスチャを使ってホログラムを制御する。
Instructions
最初にスクリプトを作成すると、"Select" ジェスチャを検出できるようになります。
- [Scripts] フォルダーで、GazeGestureManager という名前のスクリプトを作成します。
- GazeGestureManager スクリプトを、[階層] の OrigamiCollection オブジェクトにドラッグします。
- Visual Studio で GazeGestureManager スクリプトを開き、次のコードを追加します。
using UnityEngine;
using UnityEngine.XR.WSA.Input;
public class GazeGestureManager : MonoBehaviour
{
public static GazeGestureManager Instance { get; private set; }
// Represents the hologram that is currently being gazed at.
public GameObject FocusedObject { get; private set; }
GestureRecognizer recognizer;
// Use this for initialization
void Start()
{
Instance = this;
// Set up a GestureRecognizer to detect Select gestures.
recognizer = new GestureRecognizer();
recognizer.Tapped += (args) =>
{
// Send an OnSelect message to the focused object and its ancestors.
if (FocusedObject != null)
{
FocusedObject.SendMessageUpwards("OnSelect", SendMessageOptions.DontRequireReceiver);
}
};
recognizer.StartCapturingGestures();
}
// Update is called once per frame
void Update()
{
// Figure out which hologram is focused this frame.
GameObject oldFocusObject = FocusedObject;
// Do a raycast into the world based on the user's
// head position and orientation.
var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;
RaycastHit hitInfo;
if (Physics.Raycast(headPosition, gazeDirection, out hitInfo))
{
// If the raycast hit a hologram, use that as the focused object.
FocusedObject = hitInfo.collider.gameObject;
}
else
{
// If the raycast did not hit a hologram, clear the focused object.
FocusedObject = null;
}
// If the focused object changed this frame,
// start detecting fresh gestures again.
if (FocusedObject != oldFocusObject)
{
recognizer.CancelGestures();
recognizer.StartCapturingGestures();
}
}
}
- もう 1 つのスクリプトを [Scripts] フォルダーに作成し、今度は、SphereCommands という名前を付けます。
- [階層] ビューの OrigamiCollection オブジェクトを展開します。
- SphereCommands スクリプトを、[階層] パネルの Sphere1 オブジェクトにドラッグします。
- SphereCommands スクリプトを、[階層] パネルの Sphere2 オブジェクトにドラッグします。
- 編集のために Visual Studio でスクリプトを開き、既定のコードを次のコードに置き換えます。
using UnityEngine;
public class SphereCommands : MonoBehaviour
{
// Called by GazeGestureManager when the user performs a Select gesture
void OnSelect()
{
// If the sphere has no Rigidbody component, add one to enable physics.
if (!this.GetComponent<Rigidbody>())
{
var rigidbody = this.gameObject.AddComponent<Rigidbody>();
rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
}
}
}
- アプリをエクスポートしてビルドし、HoloLens エミュレーターに配置します。
- シーンを見回し、球体の 1 つが中央に位置付けます。
- Xbox コントローラーで A ボタンを押すか、Space キーを押して、"選ぶ" ジェスチャをシミュレートします。
第 4 章 - 音声
この章では、2 つの音声コマンド (落下した球体を元の場所に戻す "Reset world" と、球体を落下させる "Drop sphere") のサポートを追加します。
目標
- 常にバックグラウンドで聞こえる音声コマンドを追加する。
- 音声コマンドに反応するホログラムを作成する。
Instructions
- [Scripts] フォルダーに、SpeechManager という名前のスクリプトを作成します。
- SpeechManager スクリプトを、[階層] の OrigamiCollection オブジェクトにドラッグします
- Visual Studio で SpeechManager スクリプトを開きます。
- 次のコードをコピーして SpeechManager.cs に貼り付け、[すべて保存] をクリックします。
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.Speech;
public class SpeechManager : MonoBehaviour
{
KeywordRecognizer keywordRecognizer = null;
Dictionary<string, System.Action> keywords = new Dictionary<string, System.Action>();
// Use this for initialization
void Start()
{
keywords.Add("Reset world", () =>
{
// Call the OnReset method on every descendant object.
this.BroadcastMessage("OnReset");
});
keywords.Add("Drop Sphere", () =>
{
var focusObject = GazeGestureManager.Instance.FocusedObject;
if (focusObject != null)
{
// Call the OnDrop method on just the focused object.
focusObject.SendMessage("OnDrop", SendMessageOptions.DontRequireReceiver);
}
});
// Tell the KeywordRecognizer about our keywords.
keywordRecognizer = new KeywordRecognizer(keywords.Keys.ToArray());
// Register a callback for the KeywordRecognizer and start recognizing!
keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;
keywordRecognizer.Start();
}
private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args)
{
System.Action keywordAction;
if (keywords.TryGetValue(args.text, out keywordAction))
{
keywordAction.Invoke();
}
}
}
- Visual Studio で SphereCommands スクリプトを開きます。
- このスクリプトを次のように更新します。
using UnityEngine;
public class SphereCommands : MonoBehaviour
{
Vector3 originalPosition;
// Use this for initialization
void Start()
{
// Grab the original local position of the sphere when the app starts.
originalPosition = this.transform.localPosition;
}
// Called by GazeGestureManager when the user performs a Select gesture
void OnSelect()
{
// If the sphere has no Rigidbody component, add one to enable physics.
if (!this.GetComponent<Rigidbody>())
{
var rigidbody = this.gameObject.AddComponent<Rigidbody>();
rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
}
}
// Called by SpeechManager when the user says the "Reset world" command
void OnReset()
{
// If the sphere has a Rigidbody component, remove it to disable physics.
var rigidbody = this.GetComponent<Rigidbody>();
if (rigidbody != null)
{
rigidbody.isKinematic = true;
Destroy(rigidbody);
}
// Put the sphere back into its original local position.
this.transform.localPosition = originalPosition;
}
// Called by SpeechManager when the user says the "Drop sphere" command
void OnDrop()
{
// Just do the same logic as a Select gesture.
OnSelect();
}
}
- アプリをエクスポートしてビルドし、HoloLens エミュレーターに配置します。
- エミュレーターでは、PC のマイクサポートされており、音声に反応します。カーソルが球体の 1 つの上にくるようにビューを調整して、"Drop Sphere" と発話します。
- "Reset World"と発話し、球体を元の位置に戻します。
第 5 章 - 立体音響
この章では、アプリに音楽を追加し、特定のアクションで音響効果がトリガーされるようにします。 空間音響を使用して、3D 空間の特定の場所に効果音を設定します。
目標
- 仮想の世界でホログラムを聞く。
Instructions
- Unity 上部のメニューで [Edit] (編集) > [Project Settings] (プロジェクト設定) >[Audio] (オーディオ) の順に選択します
- [Spatializer Plugin] (Spatializer プラグイン) 設定のドロップダウンを見つけて、[MS HRTF Spatializer] を選択します。
- [Holograms] フォルダーから Ambience オブジェクトを [Hierarchy] (階層) パネルの OrigamiCollection オブジェクトにドラッグします。
- OrigamiCollection を選択し、[Audio Source] コンポーネントに移動します。 以下のプロパティを変更します。
- [空間化] プロパティをオンにします。
- [起動時に再生] をオンにします。
- スライダーを右端までドラッグして、[Spatial Blend] (空間融合) を [3D] に変更します。
- [Loop] (ループ) プロパティをオンにします。
- [3D サウンド設定] を展開し、[ドップラー レベル] に「0.1」と入力します。
- [音量ロールオフ] を [対数関数的ロールオフ] に設定します。
- [最大距離] を 20 に設定します。
- [Scripts] フォルダーで、SphereSounds という名前のスクリプトを作成します。
- SphereSounds を [Hierarchy] (階層) パネルの Sphere1 オブジェクトと Sphere2 オブジェクトにドラッグします。
- Visual Studio で SphereSounds を開き、次のようにコードを更新して [すべて保存] をクリックします。
using UnityEngine;
public class SphereSounds : MonoBehaviour
{
AudioSource impactAudioSource = null;
AudioSource rollingAudioSource = null;
bool rolling = false;
void Start()
{
// Add an AudioSource component and set up some defaults
impactAudioSource = gameObject.AddComponent<AudioSource>();
impactAudioSource.playOnAwake = false;
impactAudioSource.spatialize = true;
impactAudioSource.spatialBlend = 1.0f;
impactAudioSource.dopplerLevel = 0.0f;
impactAudioSource.rolloffMode = AudioRolloffMode.Logarithmic;
impactAudioSource.maxDistance = 20f;
rollingAudioSource = gameObject.AddComponent<AudioSource>();
rollingAudioSource.playOnAwake = false;
rollingAudioSource.spatialize = true;
rollingAudioSource.spatialBlend = 1.0f;
rollingAudioSource.dopplerLevel = 0.0f;
rollingAudioSource.rolloffMode = AudioRolloffMode.Logarithmic;
rollingAudioSource.maxDistance = 20f;
rollingAudioSource.loop = true;
// Load the Sphere sounds from the Resources folder
impactAudioSource.clip = Resources.Load<AudioClip>("Impact");
rollingAudioSource.clip = Resources.Load<AudioClip>("Rolling");
}
// Occurs when this object starts colliding with another object
void OnCollisionEnter(Collision collision)
{
// Play an impact sound if the sphere impacts strongly enough.
if (collision.relativeVelocity.magnitude >= 0.1f)
{
impactAudioSource.Play();
}
}
// Occurs each frame that this object continues to collide with another object
void OnCollisionStay(Collision collision)
{
Rigidbody rigid = gameObject.GetComponent<Rigidbody>();
// Play a rolling sound if the sphere is rolling fast enough.
if (!rolling && rigid.velocity.magnitude >= 0.01f)
{
rolling = true;
rollingAudioSource.Play();
}
// Stop the rolling sound if rolling slows down.
else if (rolling && rigid.velocity.magnitude < 0.01f)
{
rolling = false;
rollingAudioSource.Stop();
}
}
// Occurs when this object stops colliding with another object
void OnCollisionExit(Collision collision)
{
// Stop the rolling sound if the object falls off and stops colliding.
if (rolling)
{
rolling = false;
impactAudioSource.Stop();
rollingAudioSource.Stop();
}
}
}
- スクリプトを保存し、Unity に戻ります。
- アプリをエクスポートしてビルドし、HoloLens エミュレーターに配置します。
- ヘッドフォンを付けて最大効果に設定し、ステージに近づいたり、離れたりして音の変化を聞き取ります。
第 6 章 - 空間マッピング
次に、空間マッピングを使用して、現実世界の現実の物体にゲーム ボードを配置します。
目標
- 現実世界を仮想世界に取り込む。
- 最も重要な場所にホログラムを配置する。
Instructions
- [Project] (プロジェクト) パネルで [Holograms] フォルダーをクリックします。
- [Spatial Mapping] アセットを [Hierarchy] (階層) のルートにドラッグします。
- [階層] で Spatial Mapping オブジェクトをクリックします。
- [インスペクター] パネルで、次のプロパティを変更します。
- [ビジュアル メッシュの描画] チェックボックスをオンにします。
- [描画素材] を見つけ、右側の円をクリックします。 上部の検索フィールドに「wireframe」と入力します。 結果をクリックしてウィンドウを閉じます。
- アプリをエクスポートしてビルドし、HoloLens エミュレーターに配置します。
- アプリを実行すると、以前にスキャンした現実世界のリビング ルームのメッシュがワイヤーフレームにレンダリングされます。
- 転がる球体がステージから床にどのように落下するかを確認します。
次に、新しい場所に OrigamiCollection を移動する方法を示します。
- [Scripts] フォルダーに、TapToPlaceParent という名前のスクリプトを作成します。
- [階層] パネルで OrigamiCollection を展開し、Stage オブジェクトを選択します。
- TapToPlaceParent スクリプトを Stage オブジェクトにドラッグします。
- Visual Studio で TapToPlaceParent スクリプトを開き、次のようにコードを変更します。
using UnityEngine;
public class TapToPlaceParent : MonoBehaviour
{
bool placing = false;
// Called by GazeGestureManager when the user performs a Select gesture
void OnSelect()
{
// On each Select gesture, toggle whether the user is in placing mode.
placing = !placing;
// If the user is in placing mode, display the spatial mapping mesh.
if (placing)
{
SpatialMapping.Instance.DrawVisualMeshes = true;
}
// If the user is not in placing mode, hide the spatial mapping mesh.
else
{
SpatialMapping.Instance.DrawVisualMeshes = false;
}
}
// Update is called once per frame
void Update()
{
// If the user is in placing mode,
// update the placement to match the user's gaze.
if (placing)
{
// Do a raycast into the world that will only hit the Spatial Mapping mesh.
var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;
RaycastHit hitInfo;
if (Physics.Raycast(headPosition, gazeDirection, out hitInfo,
30.0f, SpatialMapping.PhysicsRaycastMask))
{
// Move this object's parent object to
// where the raycast hit the Spatial Mapping mesh.
this.transform.parent.position = hitInfo.point;
// Rotate this object's parent object to face the user.
Quaternion toQuat = Camera.main.transform.localRotation;
toQuat.x = 0;
toQuat.z = 0;
this.transform.parent.rotation = toQuat;
}
}
}
}
- アプリをエクスポートしてビルドし、配置します。
- これで、ゲームに視線を送り、Select ジェスチャ (A キーまたは Space キー) を使ってゲームを新しい場所に移動し、再度 Select ジェスチャを使用することで、特定の場所にゲームを配置できます。
終わりに
これで、このチュートリアルは終了です。
学習した内容は次のとおりです。
- Unity でホログラフィック アプリを作成する方法。
- 視線入力、ジェスチャ、音声、サウンド、空間マッピングを利用する方法。
- Visual Studio を使ってアプリをビルドおよび配置する方法。
これで、独自のホログラフィック アプリを作成する準備が整いました。