HoloLens (第 1 代) Basics 101E:使用模擬器完成專案

重要

Mixed Reality Academy 教學課程是使用 HoloLens (第 1 代) 、Unity 2017 和Mixed Reality沉浸式頭戴式裝置所設計。 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。 這些教學課程不會使用用於HoloLens 2的最新工具組或互動進行更新,而且可能與較新版本的 Unity 不相容。 系統會保留這些資訊,以繼續在支援的裝置上運作。 已針對 HoloLens 2 公佈一系列新的教學課程


本教學課程將逐步引導您完成內建 Unity 的完整專案,示範 HoloLens 上的核心Windows Mixed Reality功能,包括注視手勢語音輸入空間音效空間對應。 本教學課程大約需要 1 小時才能完成。

裝置支援

課程 HoloLens 沉浸式頭戴裝置
MR Basics 101E:使用模擬器完成專案 ✔️

在您開始使用 Intune 之前

必要條件

專案檔

  • 下載專案所需的 檔案 。 需要 Unity 2017.2 或更新版本。
    • 如果您仍然需要 Unity 5.6 支援,請使用 此版本
    • 如果您仍然需要 Unity 5.5 支援,請使用 此版本
    • 如果您仍然需要 Unity 5.4 支援,請使用 此版本
  • 將檔案解除封存到桌面或其他容易觸達的位置。 將資料夾名稱保留為 Origami

注意

如果您想要先查看原始程式碼再下載,可以在 GitHub 上取得

第 1 章 - 「Holo」 世界

在本章中,我們將設定我們的第一個 Unity 專案,並逐步執行建置和部署程式。

目標

  • 設定 Unity 以進行全像攝影開發。
  • 製作全像投影。
  • 查看您建立的全像投影。

指示

  • 啟動 Unity。
  • 選取 [開啟] 。
  • 輸入位置作為您先前未封存的 Origami 資料夾。
  • 選取 [Origami ],然後按一下 [ 選取資料夾]。
  • 儲存新的場景:檔案 / 另存場景為
  • 將場景命名為 Origami ,然後按 [ 儲存] 按鈕。

設定主相機

  • 在 [階層面板] 中,選取 [主要相機]。
  • 偵測器 中,將其轉換位置設定為 0,0,0
  • 尋找 Clear Flags 屬性,並將下拉式清單從 Skybox 變更為 純色
  • 按一下 [背景] 欄位,以開啟色彩選擇器。
  • R、G、B 和 A 設為 0

設定場景

  • 在 [ 階層] 面板中,按一下 [ 建立 ] 和 [ 建立空白]。
  • 以滑鼠右鍵按一下新的 GameObject ,然後選取 [重新命名]。 將 GameObject 重新命名為 OrigamiCollection
  • [專案面板] 的[全像投影]資料夾:
    • [階段 ] 拖曳至 [階層] 以作為 OrigamiCollection的子系。
    • Sphere1 拖曳到階層中,成為 OrigamiCollection的子系。
    • Sphere2 拖曳到階層中,成為 OrigamiCollection的子系。
  • 以滑鼠右鍵按一下 [階層] 面板中[方向光線] 物件,然後選取 [刪除]。
  • [全像投影] 資料夾,將 Lights 拖曳到 [ 階層面板] 的根目錄。
  • [階層]中,選取 OrigamiCollection
  • Inspector中,將轉換位置設定為 0、-0.5、2.0
  • 按 Unity 中的 [播放 ] 按鈕以預覽您的全像投影。
  • 您應該會在預覽視窗中看到 Origami 物件。
  • 再次按 [播放 ] 以停止預覽模式。

將專案從 Unity 匯出至 Visual Studio

  • 在 Unity 中,選取 [ 檔案 > 組建設定]。
  • [平臺] 清單中選取[Windows 市集],然後按一下 [切換平臺]。
  • SDK 設定為 通用 10 ,並將 [組建類型] 設定為 D3D
  • 檢查 Unity C# 專案
  • 按一下 [新增開啟場景 ] 以新增場景。
  • 按一下 [播放機設定...]。
  • 在 [偵測器] 面板中,選取 Windows 市集標誌。 然後選取 [發佈設定]。
  • 在 [ 功能] 區段中,選取 [麥克風 ] 和 [ SpatialPerception ] 功能。
  • 回到 [建置設定] 視窗,按一下 [ 建置]。
  • 建立名為 「App」 的新資料夾
  • 按一下 [ 應用程式資料夾]。
  • [選取資料夾]。
  • 當 Unity 完成時,就會顯示檔案總管視窗。
  • 開啟 [應用程式 ] 資料夾。
  • 開啟 Origami Visual Studio 方案
  • 使用 Visual Studio 中的頂端工具列,將目標從 [偵錯] 變更為 [ 發行 ],並將 [ARM] 變更為 [X86]。
    • 按一下 [裝置] 按鈕旁的箭號,然後選取 [HoloLens 模擬器]。
    • 按一下 [ 偵錯 - > 啟動但不偵錯 ],或按 Ctrl + F5
    • 在一段時間之後,模擬器會從 Origami 專案開始。 第一次啟動 模擬器時,模擬器可能需要 15 分鐘的時間才能啟動。 啟動之後,請勿關閉它。

第 2 章 - 注視

在本章中,我們將介紹三種與全像投影互動方式的前三種方式 -- 注視

目標

  • 使用世界鎖定游標將注視視覺化。

指示

  • 返回至 Unity 專案,如果仍開啟,請關閉 [建置設定] 視窗。
  • 選取 [專案] 面板中[全像投影] 資料夾。
  • Cursor 物件拖曳至根層級的 [ 階層] 面板
  • 按兩下 Cursor 物件,以進一步查看它。
  • 以滑鼠右鍵按一下 [專案] 面板中的 [ 腳本 ] 資料夾。
  • 按一下 [ 建立 ] 子功能表。
  • 選取 [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 物理引擎開啟重力,讓球體落落。

目標

  • 使用 [選取] 手勢來控制全像投影。

指示

我們將從建立腳本開始,而不是偵測到選取手勢。

  • 在 [ 腳本 ] 資料夾中,建立名為 GazeGestureManager 的腳本。
  • GazeGestureManager 腳本拖曳至 Hierarchy 中的 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();
        }
    }
}
  • 在 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 模擬器。
  • 查看場景,並置中其中一個球體。
  • 按 Xbox 控制器上的 [A] 按鈕,或按空格鍵來模擬 [選取] 手勢。

第 4 章 - 語音

在本章中,我們將新增兩個 語音命令的支援:「重設世界」,以將捨棄的球體傳回至其原始位置,以及「置放球體」以讓球體落下。

目標

  • 新增一律在背景中接聽的語音命令。
  • 建立回應語音命令的全像投影。

指示

  • 在 [ 腳本 ] 資料夾中,建立名為 SpeechManager 的腳本。
  • SpeechManager 腳本拖曳至 Hierarchy 中的 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 模擬器。
  • 模擬器將支援電腦的麥克風並回應您的語音:調整檢視,讓游標位於其中一個球體上,並說出「Drop Sphere」。
  • 說「重設世界」,讓他們回到其初始位置。

第 5 章 - 空間音效

在本章中,我們會將音樂新增至應用程式,然後在特定動作上觸發音效。 我們將使用 空間音效 來提供 3D 空間中的特定位置。

目標

  • 聆聽您世界中的全像投影。

指示

  • 在 Unity 中,從頂端功能表中選取 [編輯 > 專案設定音訊] >
  • 尋找 Spatializer 外掛程式 設定,然後選取 [MS HRTF Spatializer]。
  • Holograms 資料夾中,將 [元素] 拖曳到 [階層] 面板中的 OrigamiCollection 物件。
  • 選取 [OrigamiCollection ],然後尋找 [音訊來源 ] 元件。 變更下列屬性:
    • 檢查 Spatialize 屬性。
    • 檢查 [在喚醒時播放]。
    • 將滑杆拖曳到右邊,將 空間混合 變更為 3D
    • 檢查 Loop 屬性。
    • 展開[3D 音效設定],然後針對Doppler 層級輸入0.1
    • [磁片區變換 ] 設定為 [對數輪詢]。
    • [最大距離] 設定為 20
  • 在 [ 腳本 ] 資料夾中,建立名為 SphereSounds 的腳本。
  • SphereSounds 拖曳至 Hierarchy 中的 Sphere1Sphere2 物件。
  • 在 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 章 - 空間對應

現在,我們將使用 空間對應 ,將遊戲台放在真實世界中的實際物件上。

目標

  • 將您的真實世界帶入虛擬世界。
  • 將您的全像投影放在您最重要的位置。

指示

  • 按一下 [專案] 面板中的 [全像投影 ] 資料夾。
  • 空間對應 資產拖曳至 階層的根目錄。
  • 按一下 [階層] 中的 [空間對應 ] 物件。
  • 在 [ 偵測器] 面板中,變更下列屬性:
    • 取 [繪製視覺網格] 方塊
    • 找出 [繪製材質 ],然後按一下右邊的圓形。 在頂端的搜尋欄位中輸入 「wireframe」。 按一下結果,然後關閉視窗。
  • 將應用程式匯出、建置及部署至 HoloLens 模擬器。
  • 當應用程式執行時,先前掃描的實際會議室網格將會以線框呈現。
  • 觀看滾動球如何落下階段,並落在樓層!

現在我們將示範如何將 OrigamiCollection 移至新位置:

  • 在 [ 腳本 ] 資料夾中,建立名為 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;
            }
        }
    }
}
  • 匯出、建置和部署應用程式。
  • 現在,您應該能夠將遊戲放在特定位置,方法是使用選取手勢 (A 或空格鍵) ,然後移至新的位置,然後再次使用 [選取] 手勢。

結束

這就是本教學課程的結尾!

您已了解︰

  • 如何在 Unity 中建立全像攝影應用程式。
  • 如何使用注視、手勢、語音、音效和空間對應。
  • 如何使用 Visual Studio 建置和部署應用程式。

您現在已準備好開始建立自己的全像攝影應用程式!

另請參閱