HoloLens (第 1 代) Input 211: 手勢
重要
Mixed Reality Academy 教學課程是使用 HoloLens (第 1 代) 、Unity 2017 和 Mixed Reality 沈浸式頭戴式裝置所設計。 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。 這些教學課程不會使用用於 HoloLens 2 的最新工具組或互動進行更新,而且可能與較新版本的 Unity 不相容。 系統會保留這些資訊,以繼續在支援的裝置上運作。 已針對 HoloLens 2 公佈一系列新的教學課程。
手勢會將 使用者意圖變成動作。 透過手勢,使用者可以與全像投影互動。 在此課程中,我們將瞭解如何追蹤使用者的手部、回應使用者輸入,並根據手部狀態和位置提供意見反應給使用者。
在 MR Basics 101 中,我們使用簡單的空中點選手勢來與全像投影互動。 現在,我們將超越空中點選手勢,並探索新概念以:
- 偵測使用者手的追蹤時機,並提供意見反應給使用者。
- 使用導覽手勢來旋轉全像投影。
- 當使用者的手即將離開檢視時提供意見反應。
- 使用操作事件可讓使用者使用手部移動全像投影。
在此課程中,我們將重新流覽 Unity 專案 模型總管,我們建置於 MR Input 210 中。 我們的太空人朋友回到協助我們探索這些新的手勢概念。
重要
下列每章內嵌的影片都是使用舊版 Unity 和 Mixed Reality Toolkit 錄製。 雖然逐步指示正確且目前,但您可能會在對應的影片中看到過期的腳本和視覺效果。 影片仍包含海報,因為涵蓋的概念仍適用。
裝置支援
課程 | HoloLens | 沉浸式頭戴裝置 |
---|---|---|
MR Input 211:手勢 | ✔️ | ✔️ |
在您開始使用 Intune 之前
必要條件
- 已安裝正確工具的 Windows 10 計算機。
- 一些基本的 C# 程式設計能力。
- 您應該已完成 MR Basics 101。
- 您應該已完成 MR Input 210。
- 已 設定用於開發的 HoloLens 裝置。
專案檔
- 下載專案所需的 檔案 。 需要 Unity 2017.2 或更新版本。
- 將檔案解除封存到桌面或其他容易觸達的位置。
注意
如果您想要在下載之前查看原始程式碼,可在 GitHub 上取得。
Errata 和 Notes
- 必須在 Visual Studio 的 [工具->選項偵>錯] 下停用 [啟用 Just My Code] (未核取的) ,才能在程式代碼中叫用斷點。
第 0 章 - Unity 設定
指示
- 啟動 Unity。
- 選取 [開啟]。
- 流覽至您先前未封存的 Gesture 資料夾。
- 尋找並選取 [啟動模型總管/] 資料夾。
- 按兩下 [ 選取資料夾] 按鈕。
- 在 [專案] 面板中,展開 [場景] 資料夾。
- 按兩下 ModelExplorer 場景,以在 Unity 中載入它。
建置
- 在 Unity 中,選取 [ 檔案 > 建置設定]。
- 如果 Scenes/ModelExplorer 未列在 [建置中的場景] 中,請按兩下 [ 新增開啟場景 ] 以新增場景。
- 如果您特別針對 HoloLens 進行開發,請將 目標裝置 設定為 HoloLens。 否則,請將它保留在任何 裝置上。
- 確定 [組建類型 ] 設定為 D3D ,且 SDK 已設定為 [最新安裝 ] (,這應該是 SDK 16299 或更新版本) 。
- 按一下 [建置]。
- 建立名為 「App」 的新資料夾 。
- 按兩下 [ 應用程式 ] 資料夾。
- 按 [選取資料夾 ],Unity 會開始建置Visual Studio的專案。
當 Unity 完成時,會出現 檔案總管 視窗。
- 開啟 [應用程式 ] 資料夾。
- 開啟 ModelExplorer Visual Studio 方案。
如果部署至 HoloLens:
- 使用 Visual Studio 中的頂端工具列,將目標從 [偵錯] 變更為 [發行 ],並將目標從 ARM 變更為 x86。
- 按兩下 [本機計算機] 按鈕旁邊的下拉式箭號,然後選取 [ 遠端計算機]。
- 輸入您的 HoloLens 裝置 IP 位址 ,並將 [驗證模式] 設定為 [通用] ([未加密通訊協定]) 。 按一下 [選取]。 如果您不知道裝置 IP 位址,請查看 [設定 > 網络] & [因特網 > 進階選項]。
- 在頂端功能表欄中,按一下 [偵錯 - 啟動但不>偵錯],或按 Ctrl + F5。 如果這是第一次部署到您的裝置,您必須 將它與 Visual Studio 配對。
- 部署應用程式時,請使用選取手勢關閉 Fitbox。
如果部署至沉浸式頭戴裝置:
- 使用 Visual Studio 中的頂端工具列,將目標從 [偵錯] 變更為 [發行 ],並將目標從 ARM 變更為 x64。
- 請確定部署目標已設定為 本機計算機。
- 在頂端功能表欄中,按一下 [偵錯 - 啟動但不>偵錯],或按 Ctrl + F5。
- 當應用程式已部署時,藉由提取動作控制器上的觸發程式來關閉 Fitbox 。
注意
您可能會在 Visual Studio [錯誤] 面板中注意到一些紅色錯誤。 您可以放心地忽略它們。 切換至 [輸出] 面板以檢視實際的建置進度。 [輸出] 面板中的錯誤會要求您進行修正 (最常見的原因是腳本) 發生錯誤。
第 1 章 - 手部偵測到的意見反應
目標
- 訂閱手部追蹤事件。
- 使用游標意見反應,在追蹤手部時向用戶顯示。
注意
在 HoloLens 2 上,每當手指指向) 時,手部就會偵測到引發 (。
指示
- 在 [ 階層] 面板中,展開 InputManager 物件。
- 尋找並選取 GesturesInput 物件。
InteractionInputSource.cs 腳本會執行下列步驟:
- 訂閱 InteractionSourceDetected 和 InteractionSourceLost 事件。
- 設定 HandDetected 狀態。
- 取消訂閱 InteractionSourceDetected 和 InteractionSourceLost 事件。
接下來,我們會將游標從 MR Input 210 升級為一個,根據使用者的動作來顯示意見反應。
- 在 [ 階層] 面板中,選取 Cursor 物件並加以刪除。
- 在 [專案] 面板中,搜尋 CursorWithFeedback 並將它拖曳到 [階層 ] 面板。
- 按兩下 [階層] 面板中的 InputManager,然後將 CursorWithFeedback 物件從 [階層] 拖曳到 Inspector 底部的 InputManager 的 SimpleSinglePointerSelector 的 Cursor字段。
- 按兩下 [階層] 中的 CursorWithFeedback。
- 在 [偵測器] 面板中,展開 [對象數據指標] 腳本上的 [數據指標狀態數據]。
資料指標狀態資料的運作方式如下:
- 任何 觀察 狀態都表示不會偵測到任何手部,而且使用者只是看一下。
- 任何 互動 狀態都表示偵測到手部或控制器。
- 任何 暫留 狀態表示使用者正在查看全像投影。
建置和部署
- 在 Unity 中,使用 檔案 > 建置設定 來重建應用程式。
- 開啟 [應用程式 ] 資料夾。
- 如果尚未開啟,請開啟 ModelExplorer Visual Studio 方案。
- (如果您在設定期間已在 Visual Studio 中建置/部署此專案,則可以開啟該 VS 實例,並在出現提示時按兩下 [全部重載]) 。
- 在 Visual Studio 中,按兩下 [ 偵錯 -> 啟動但不偵 錯],或按 Ctrl + F5。
- 應用程式部署至 HoloLens 之後,請使用空中點選手勢關閉 fitbox。
- 將手移至檢視,並將您的手指指向空,以開始手部追蹤。
- 將手左、右、向上和向下移動。
- 監看游標在偵測到手部時如何變更,然後從檢視中遺失。
- 如果您是在沉浸式頭戴式裝置上,則必須連線並中斷控制器的連線。 此意見反應在沉浸式裝置上變得較不有趣,因為連線控制器一律會「可用」。
第 2 章 - 導覽
目標
- 使用導覽手勢事件來旋轉太空人。
指示
若要在應用程式中使用瀏覽手勢,我們將編輯 GestureAction.cs ,以在導航手勢發生時旋轉物件。 此外,我們會將意見反應新增至游標,以在導覽可用時顯示。
- 在 [ 階層] 面板中,展開 [CursorWithFeedback]。
- 在 Holograms 資料夾中,尋找 ScrollFeedback 資產。
- 將 ScrollFeedback 預製專案拖放到 Hierarchy 中的 CursorWithFeedback GameObject。
- 按兩下 CursorWithFeedback。
- 在 [偵測器] 面板中,按兩下 [ 新增元件 ] 按鈕。
- 在功能表中,輸入搜尋方塊 CursorFeedback。 選取搜尋結果。
- 將 ScrollFeedback 物件從階層拖放到 Inspector 中 Cursor Feedback 元件中的 Scroll Detected Game Object 屬性。
- 在 [ 階層] 面板中,選取 AstroMan 物件。
- 在 [偵測器] 面板中,按兩下 [ 新增元件 ] 按鈕。
- 在功能表中,輸入搜尋方塊 手勢動作。 選取搜尋結果。
接下來,在Visual Studio中開啟 GestureAction.cs 。 在撰寫程式代碼練習 2.c 時,編輯腳本以執行下列動作:
- 每當執行 Navigation 手勢時,旋轉 AstroMan 物件。
- 計算 rotationFactor ,以控制套用至物件的旋轉量。
- 當使用者向左或向右移動其手部時,繞著Y軸旋轉物件。
在文稿中完成程式代碼撰寫練習 2.c,或以下列已完成的解決方案取代程式代碼:
using HoloToolkit.Unity.InputModule;
using UnityEngine;
/// <summary>
/// GestureAction performs custom actions based on
/// which gesture is being performed.
/// </summary>
public class GestureAction : MonoBehaviour, INavigationHandler, IManipulationHandler, ISpeechHandler
{
[Tooltip("Rotation max speed controls amount of rotation.")]
[SerializeField]
private float RotationSensitivity = 10.0f;
private bool isNavigationEnabled = true;
public bool IsNavigationEnabled
{
get { return isNavigationEnabled; }
set { isNavigationEnabled = value; }
}
private Vector3 manipulationOriginalPosition = Vector3.zero;
void INavigationHandler.OnNavigationStarted(NavigationEventData eventData)
{
InputManager.Instance.PushModalInputHandler(gameObject);
}
void INavigationHandler.OnNavigationUpdated(NavigationEventData eventData)
{
if (isNavigationEnabled)
{
/* TODO: DEVELOPER CODING EXERCISE 2.c */
// 2.c: Calculate a float rotationFactor based on eventData's NormalizedOffset.x multiplied by RotationSensitivity.
// This will help control the amount of rotation.
float rotationFactor = eventData.NormalizedOffset.x * RotationSensitivity;
// 2.c: transform.Rotate around the Y axis using rotationFactor.
transform.Rotate(new Vector3(0, -1 * rotationFactor, 0));
}
}
void INavigationHandler.OnNavigationCompleted(NavigationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void INavigationHandler.OnNavigationCanceled(NavigationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void IManipulationHandler.OnManipulationStarted(ManipulationEventData eventData)
{
if (!isNavigationEnabled)
{
InputManager.Instance.PushModalInputHandler(gameObject);
manipulationOriginalPosition = transform.position;
}
}
void IManipulationHandler.OnManipulationUpdated(ManipulationEventData eventData)
{
if (!isNavigationEnabled)
{
/* TODO: DEVELOPER CODING EXERCISE 4.a */
// 4.a: Make this transform's position be the manipulationOriginalPosition + eventData.CumulativeDelta
}
}
void IManipulationHandler.OnManipulationCompleted(ManipulationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void IManipulationHandler.OnManipulationCanceled(ManipulationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void ISpeechHandler.OnSpeechKeywordRecognized(SpeechEventData eventData)
{
if (eventData.RecognizedText.Equals("Move Astronaut"))
{
isNavigationEnabled = false;
}
else if (eventData.RecognizedText.Equals("Rotate Astronaut"))
{
isNavigationEnabled = true;
}
else
{
return;
}
eventData.Use();
}
}
您會注意到其他導覽事件已經填入一些資訊。 我們會將 GameObject 推送至工具組的 InputSystem 強制響應堆疊,因此使用者不需要在開始旋轉之後,將焦點保留在太空人上。 相對地,我們會在手勢完成之後,從堆疊中快顯 GameObject。
建置和部署
- 在 Unity 中重建應用程式,然後從 Visual Studio 建置和部署,以在 HoloLens 中執行該應用程式。
- 注視太空人,兩個箭號應該出現在游標的任一端。 這個新的視覺效果表示太空人可以旋轉。
- 將手放在指向空) (指的就緒位置,讓 HoloLens 開始追蹤手部。
- 若要旋轉太空人,請將索引指下角至捏合位置,然後向左或向右移動您的手以觸發 NavigationX 手勢。
第 3 章 - 手部指引
目標
- 使用 手部指引分數 來協助預測手部追蹤何時遺失。
- 提供 游標的意見反應 ,以在使用者手接近相機的檢視邊緣時顯示。
指示
- 在 [ 階層] 面板中,選取 CursorWithFeedback 物件。
- 在 [偵測器] 面板中,按兩下 [ 新增元件 ] 按鈕。
- 在功能表中,輸入搜尋方塊的 [ 手部指引]。 選取搜尋結果。
- 在 [項目 面板 全像投影] 資料夾中,尋找 HandGuidanceFeedback 資產。
- 將 HandGuidanceFeedback 資產拖放到 [偵測器] 面板中的 [手部指引指標] 屬性。
建置和部署
- 在 Unity 中重建應用程式,然後從 Visual Studio 建置和部署,以體驗 HoloLens 上的應用程式。
- 將您的手帶入檢視,並引發您的索引指以追蹤。
- 使用導覽手勢開始旋轉太空人, (將索引指和指尖捏合在一起) 。
- 將手向左、向右、向上和向下移動。
- 當您的手接近手勢框架的邊緣時,游標旁邊應該會出現箭號,警告您手部追蹤將會遺失。 箭號會指出要移動手的方向,以防止追蹤遺失。
第 4 章 - 操作
目標
- 使用操作事件以手部移動太空人。
- 提供游標的意見反應,讓使用者知道何時可以使用操作。
指示
GestureManager.cs 和 AstronautManager.cs 可讓我們執行下列動作:
- 使用語音關鍵詞 「移動太空人」來啟用 操作 手勢和「旋轉太空人」來停用它們。
- 切換以回應 操作手勢辨識器。
現在就開始吧。
- 在 [ 階層] 面板中,建立新的空白 GameObject。 將它命名為 「AstronautManager」。
- 在 [偵測器] 面板中,按兩下 [ 新增元件 ] 按鈕。
- 在功能表中,於搜尋方塊中輸入 太空人管理員。 選取搜尋結果。
- 在 [偵測器] 面板中,按兩下 [ 新增元件 ] 按鈕。
- 在功能表中,於搜尋方塊中輸入 語音輸入來源。 選取搜尋結果。
我們現在會新增控制太空人互動狀態所需的語音命令。
- 展開 Inspector 中的 [關鍵詞] 區段。
- +按下右側的 以新增關鍵詞。
- 將關鍵字輸入為 移動太空人。 如有需要,請隨意新增按鍵快捷方式。
- +按下右側的 以新增關鍵詞。
- 將關鍵字輸入為 旋轉太空人。 如有需要,請隨意新增按鍵快捷方式。
- 您可以在 ISpeechHandler.OnSpeechKeywordRecognized 處理程式的 GestureAction.cs 中找到對應的處理程式程式代碼。
接下來,我們會在游標上設定操作意見反應。
- 在 [專案 ] 面板中的 [全像投影 ] 資料夾中,尋找 PathingFeedback 資產。
- 將 PathingFeedback 預製專案拖放到 Hierarchy 中的 CursorWithFeedback 物件。
- 在 [ 階層] 面板中,按兩下 [ CursorWithFeedback]。
- 將 PathingFeedback 物件從 Hierarchy 拖放到 Inspector 中 Cursor Feedback 元件中的 Pathing Detected Game Object 属性。
現在,我們需要將程式代碼新增至 GestureAction.cs ,才能啟用下列專案:
- 將程式代碼新增至 IManipulationHandler.OnManipulationUpdated 函式,這會在偵測到 操作 手勢時移動太空人。
- 計算 移動向量 ,以根據手部位置判斷太空人應移至的位置。
- 將 太空人移至新位置。
在 GestureAction.cs 中完成程式代碼撰寫練習 4.a,或使用下列已完成的解決方案:
using HoloToolkit.Unity.InputModule;
using UnityEngine;
/// <summary>
/// GestureAction performs custom actions based on
/// which gesture is being performed.
/// </summary>
public class GestureAction : MonoBehaviour, INavigationHandler, IManipulationHandler, ISpeechHandler
{
[Tooltip("Rotation max speed controls amount of rotation.")]
[SerializeField]
private float RotationSensitivity = 10.0f;
private bool isNavigationEnabled = true;
public bool IsNavigationEnabled
{
get { return isNavigationEnabled; }
set { isNavigationEnabled = value; }
}
private Vector3 manipulationOriginalPosition = Vector3.zero;
void INavigationHandler.OnNavigationStarted(NavigationEventData eventData)
{
InputManager.Instance.PushModalInputHandler(gameObject);
}
void INavigationHandler.OnNavigationUpdated(NavigationEventData eventData)
{
if (isNavigationEnabled)
{
/* TODO: DEVELOPER CODING EXERCISE 2.c */
// 2.c: Calculate a float rotationFactor based on eventData's NormalizedOffset.x multiplied by RotationSensitivity.
// This will help control the amount of rotation.
float rotationFactor = eventData.NormalizedOffset.x * RotationSensitivity;
// 2.c: transform.Rotate around the Y axis using rotationFactor.
transform.Rotate(new Vector3(0, -1 * rotationFactor, 0));
}
}
void INavigationHandler.OnNavigationCompleted(NavigationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void INavigationHandler.OnNavigationCanceled(NavigationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void IManipulationHandler.OnManipulationStarted(ManipulationEventData eventData)
{
if (!isNavigationEnabled)
{
InputManager.Instance.PushModalInputHandler(gameObject);
manipulationOriginalPosition = transform.position;
}
}
void IManipulationHandler.OnManipulationUpdated(ManipulationEventData eventData)
{
if (!isNavigationEnabled)
{
/* TODO: DEVELOPER CODING EXERCISE 4.a */
// 4.a: Make this transform's position be the manipulationOriginalPosition + eventData.CumulativeDelta
transform.position = manipulationOriginalPosition + eventData.CumulativeDelta;
}
}
void IManipulationHandler.OnManipulationCompleted(ManipulationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void IManipulationHandler.OnManipulationCanceled(ManipulationEventData eventData)
{
InputManager.Instance.PopModalInputHandler();
}
void ISpeechHandler.OnSpeechKeywordRecognized(SpeechEventData eventData)
{
if (eventData.RecognizedText.Equals("Move Astronaut"))
{
isNavigationEnabled = false;
}
else if (eventData.RecognizedText.Equals("Rotate Astronaut"))
{
isNavigationEnabled = true;
}
else
{
return;
}
eventData.Use();
}
}
建置和部署
- 在 Unity 中重建,然後從 Visual Studio 建置和部署,以在 HoloLens 中執行應用程式。
- 將手移到 HoloLens 前面,並舉起您的食指,以便追蹤它。
- 將游標放在太空人上方。
- 說「移動太空人」,以操作手勢移動太空人。
- 四個箭號應該會出現在游標周圍,以指出程式現在會回應Manipulation事件。
- 將食指向下向下放至您的指紋,並將它們保持捏合在一起。
- 當您四處移動時,太空人會移動太 (這是操作) 。
- 舉起您的食指,停止操作太空人。
- 注意:如果您在移動手之前未說出「移動太空人」,則會改用導覽手勢。
- 說「旋轉太空人」以返回可旋轉的狀態。
第 5 章 - 模型擴充
目標
- 將太空人模型展開成使用者可以互動的多個較小片段。
- 使用導覽和操作手勢個別移動每個片段。
指示
在本節中,我們將完成下列工作:
- 新增關鍵詞 「Expand Model」 以展開太空人模型。
- 新增關鍵詞「重設模型」,以將模型傳回其原始形式。
我們將這兩個關鍵詞新增至上一章的語音輸入來源。 我們也將示範另一種處理辨識事件的方式。
- 按兩下 [偵測器] 中的 [太空人][管理],然後展開 [偵測器] 中的 [關鍵詞] 區段。
- 按下右側的 + 以新增關鍵詞。
- 將關鍵字輸入為 展開模型。 如有需要,請隨意新增按鍵快捷方式。
- 按下右側的 + 以新增關鍵詞。
- 輸入關鍵詞作為 重設模型。 如有需要,請隨意新增按鍵快捷方式。
- 在 [ 偵測器] 面板中,按兩下 [ 新增元件] 按鈕。
- 在功能表中,輸入搜尋方塊 語音輸入處理程式。 選取搜尋結果。
- 核取 [是全域接聽程式],因為我們希望這些命令能夠運作,而不論我們要專注的 GameObject 為何。
- +按兩下按鈕,然後從 [關鍵詞] 下拉式清單中選取 [展開模型]。
- 按兩下 [ + 回應] 底下的 ,然後將 [太空人][管理 ] 從 [階層 ] 拖曳到 [ 無] ([物件) ] 字段。
- 現在,按兩下 [ 無函式 ] 下拉式清單,選取 [ 太空人][管理],然後 選取 [ExpandModelCommand]。
- 按兩下 [語音輸入處理程式] + 按鈕,然後從 [關鍵詞] 下拉式清單中選取 [ 重設模型 ]。
- 按兩下 [ + 回應] 底下的 ,然後將 [太空人][管理 ] 從 [階層 ] 拖曳到 [ 無] ([物件) ] 字段。
- 現在,按兩下 [ 無函 式] 下拉式清單,選取 [ 太空人][管理],然後選取 [ ResetModelCommand]。
建置和部署
- 試試看! 建置應用程式並將其部署至 HoloLens。
- 假設 展開模型 以查看展開的太空人模型。
- 使用 導覽 來旋轉太空人套件的個別片段。
- 假設 移動太空人 ,然後使用 操作 來移動太空人套件的個別片段。
- 說 「旋轉太空人 」再次旋轉片段。
- 假設 重設模型 以將太空人傳回其原始表單。
結束
恭喜! 您現在已完成 MR Input 211:手勢。
- 您知道如何偵測及回應手部追蹤、流覽和操作事件。
- 您了解導覽和操作手勢之間的差異。
- 您知道如何變更游標,以提供偵測到手部時、手部即將遺失時,以及當物件支援不同的互動時, (導覽與操作) 。