本文將以官方案例來說明如何實現(xiàn)移動全息對象操作(211 - chapter4)栖忠。此案例主要涉及到了語音狸相、手勢識別。
實現(xiàn)思路:
- 通過添加的關(guān)鍵字來初始化KeywordRecognizer瘸右;
- 創(chuàng)建一個GestureRecognizer用于實現(xiàn)Manipulation Holographic;
- 通過語音識別調(diào)用對應(yīng)的函數(shù)操作實現(xiàn)選擇不同的GestureRecognizer;
- 通過不同的手勢識別操作來對應(yīng)地向Gaze射線凝視的物體發(fā)送消息實現(xiàn)操作;
以MSDN上官網(wǎng)的demo為例:
Paste_Image.png
首先可以創(chuàng)建一個空物體來管理相關(guān)的Gaze肃晚、Hand惋鸥、Gesture相關(guān)操作。在這里我們將對全息對象的管理腳本(也就是包含語音操作命令)也掛載在此空物體Manager上。
語音輸入 Voice Command
- 聲明一個KeywordRecognizer ;
- 聲明一個
Dictionary<string, KeywordAction> keywordCollection
用于保存關(guān)鍵字和對應(yīng)的關(guān)鍵字函數(shù); - 在Start()函數(shù)中進(jìn)行添加語音關(guān)鍵字暮胧;
- 在Start()函數(shù)中由添加的關(guān)鍵字字典keywordCollection進(jìn)行對KeywordRecognizer 初始化并開始關(guān)鍵字識別;
- 對關(guān)鍵字對應(yīng)的操作函數(shù)進(jìn)行編寫。此案例中為MoveAstronautCommand函數(shù),主要實現(xiàn)將GestureManager.cs腳本中的不同的GestureRecognizer進(jìn)行切換;
**AstronautManager.cs**
using HoloToolkit;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.Speech;
public class AstronautManager : Singleton<AstronautManager>
{
// KeywordRecognizer object.
KeywordRecognizer keywordRecognizer;
// Defines which function to call when a keyword is recognized.
delegate void KeywordAction(PhraseRecognizedEventArgs args);
Dictionary<string, KeywordAction> keywordCollection;
void Start()
{
keywordCollection = new Dictionary<string, KeywordAction>();
// Add keyword to start manipulation.
keywordCollection.Add("Move Astronaut", MoveAstronautCommand);
// Initialize KeywordRecognizer with the previously added keywords.
keywordRecognizer = new KeywordRecognizer(keywordCollection.Keys.ToArray());
keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;
keywordRecognizer.Start();
}
private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args)
{
KeywordAction keywordAction;
if (keywordCollection.TryGetValue(args.text, out keywordAction))
{
keywordAction.Invoke(args);
}
}
private void MoveAstronautCommand(PhraseRecognizedEventArgs args)
{
GestureManager.Instance.Transition(GestureManager.Instance.ManipulationRecognizer);
}
void OnDestroy()
{
keywordRecognizer.Dispose();
}
}
手勢輸入 Gesture Input
手勢識別是HoloLens交互的重要輸入方法之一薯演。HoloLens提供了底層API和高層API,可以滿足不同的手勢定制需求帝嗡。底層API能夠獲取手的位置和速度信息巢寡,高層API則借助手勢識別器來識別預(yù)設(shè)的手勢(包括,單擊舆蝴、雙擊谦絮、長按菱皆、平移等等)。本部分主要是高級API使用挨稿,通過輸入源來識別手勢仇轻。
只需要很少的步驟就能使用GestureRecognizer集成手勢識別:
- 創(chuàng)建GestureRecognizer實例
- 注冊指定的手勢類型
- 訂閱手勢事件
- 開始手勢識別
**GestureManager.cs**
using HoloToolkit;
using UnityEngine;
using UnityEngine.VR.WSA.Input;
public class GestureManager : Singleton<GestureManager>
{
// Manipulation gesture recognizer.
public GestureRecognizer ManipulationRecognizer { get; private set; }
// Currently active gesture recognizer.
//此腳本原先有多個GestureManager ,因此由此代表當(dāng)前激活的GestureManager
public GestureRecognizer ActiveRecognizer { get; private set; }
public bool IsManipulating { get; private set; }
public Vector3 ManipulationPosition { get; private set; }
void Awake()
{
// Instantiate the ManipulationRecognizer.
ManipulationRecognizer = new GestureRecognizer();
// Add the ManipulationTranslate GestureSetting to the ManipulationRecognizer's RecognizableGestures.
ManipulationRecognizer.SetRecognizableGestures(
GestureSettings.ManipulationTranslate);
// Register for the Manipulation events on the ManipulationRecognizer.
ManipulationRecognizer.ManipulationStartedEvent += ManipulationRecognizer_ManipulationStartedEvent;
ManipulationRecognizer.ManipulationUpdatedEvent += ManipulationRecognizer_ManipulationUpdatedEvent;
ManipulationRecognizer.ManipulationCompletedEvent += ManipulationRecognizer_ManipulationCompletedEvent;
ManipulationRecognizer.ManipulationCanceledEvent += ManipulationRecognizer_ManipulationCanceledEvent;
}
void OnDestroy()
{
// Unregister the Manipulation events on the ManipulationRecognizer.
ManipulationRecognizer.ManipulationStartedEvent -= ManipulationRecognizer_ManipulationStartedEvent;
ManipulationRecognizer.ManipulationUpdatedEvent -= ManipulationRecognizer_ManipulationUpdatedEvent;
ManipulationRecognizer.ManipulationCompletedEvent -= ManipulationRecognizer_ManipulationCompletedEvent;
ManipulationRecognizer.ManipulationCanceledEvent -= ManipulationRecognizer_ManipulationCanceledEvent;
}
/// <summary>
/// Transition to a new GestureRecognizer.
/// </summary>
/// <param name="newRecognizer">The GestureRecognizer to transition to.</param>
public void Transition(GestureRecognizer newRecognizer) //切換此腳本中的兩個不同功能的手勢識別
{
if (newRecognizer == null) //切換手勢識別必須指定一個Recognizer
{
return;
}
if (ActiveRecognizer != null)
{
if (ActiveRecognizer == newRecognizer) //如果切換的新的手勢識別是現(xiàn)在正激活的手勢識別奶甘,就說明沒必要切換篷店,直接return
{
return;
}
ActiveRecognizer.CancelGestures();
ActiveRecognizer.StopCapturingGestures();
}
newRecognizer.StartCapturingGestures(); //此腳本中的兩個手勢識別都是由此語句激活開始的
ActiveRecognizer = newRecognizer;
}
private void ManipulationRecognizer_ManipulationStartedEvent(InteractionSourceKind source, Vector3 position, Ray ray)
{
if (HandsManager.Instance.FocusedGameObject != null)
{
IsManipulating = true;
ManipulationPosition = position;
//HandsManager.Instance.FocusedGameObject追究到下面就是Gaze射線凝視的對象
HandsManager.Instance.FocusedGameObject.SendMessageUpwards("PerformManipulationStart", position);
}
}
private void ManipulationRecognizer_ManipulationUpdatedEvent(InteractionSourceKind source, Vector3 position, Ray ray)
{
if (HandsManager.Instance.FocusedGameObject != null)
{
IsManipulating = true;
ManipulationPosition = position;
HandsManager.Instance.FocusedGameObject.SendMessageUpwards("PerformManipulationUpdate", position);
}
}
private void ManipulationRecognizer_ManipulationCompletedEvent(InteractionSourceKind source, Vector3 position, Ray ray)
{
IsManipulating = false;
}
private void ManipulationRecognizer_ManipulationCanceledEvent(InteractionSourceKind source, Vector3 position, Ray ray)
{
IsManipulating = false;
}
}
此腳本中在訂閱的手勢事件中對Gaze凝視的對象進(jìn)行SendMessageUpwards發(fā)送消息:
- 在
ManipulationRecognizer_ManipulationStartedEvent
中對Gaze凝視的對象發(fā)送的是PerformManipulationStart
函數(shù); - 在
ManipulationRecognizer_ManipulationUpdatedEvent
中對Gaze凝視的對象發(fā)送的是PerformManipulationUpdate
函數(shù)臭家;
Holographic Action 對象函數(shù)動作
**GestureAction**
using UnityEngine;
/// <summary>
/// GestureAction performs custom actions based on
/// which gesture is being performed.
/// </summary>
public class GestureAction : MonoBehaviour
{
private Vector3 manipulationPreviousPosition;
void PerformManipulationStart(Vector3 position)
{
manipulationPreviousPosition = position;
}
void PerformManipulationUpdate(Vector3 position)
{
if (GestureManager.Instance.IsManipulating)
{
Vector3 moveVector = Vector3.zero;
//Calculate the moveVector as position - manipulationPreviousPosition.
moveVector = position - manipulationPreviousPosition;
//Update the manipulationPreviousPosition with the current position.
manipulationPreviousPosition = position;
// Increment this transform's position by the moveVector.
transform.position += moveVector;
}
}
}