本文将以官方案例来说明如何实现移动全息对象操作(211 - chapter4)。此案例主要涉及到了语音、手势识别。
实现思路:
- 通过添加的关键字来初始化KeywordRecognizer;
- 创建一个GestureRecognizer用于实现Manipulation Holographic;
- 通过语音识别调用对应的函数操作实现选择不同的GestureRecognizer;
- 通过不同的手势识别操作来对应地向Gaze射线凝视的物体发送消息实现操作;
以MSDN上官网的demo为例:
首先可以创建一个空物体来管理相关的Gaze、Hand、Gesture相关操作。在这里我们将对全息对象的管理脚本(也就是包含语音操作命令)也挂载在此空物体Manager上。
语音输入 Voice Command
- 声明一个KeywordRecognizer ;
- 声明一个
Dictionary<string, KeywordAction> keywordCollection
用于保存关键字和对应的关键字函数; - 在Start()函数中进行添加语音关键字;
- 在Start()函数中由添加的关键字字典keywordCollection进行对KeywordRecognizer 初始化并开始关键字识别;
- 对关键字对应的操作函数进行编写。此案例中为MoveAstronautCommand函数,主要实现将GestureManager.cs脚本中的不同的GestureRecognizer进行切换;
**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则借助手势识别器来识别预设的手势(包括,单击、双击、长按、平移等等)。本部分主要是高级API使用,通过输入源来识别手势。
只需要很少的步骤就能使用GestureRecognizer集成手势识别:
- 创建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 ,因此由此代表当前激活的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) //如果切换的新的手势识别是现在正激活的手势识别,就说明没必要切换,直接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凝视的对象进行SendMessageUpwards发送消息:
- 在
ManipulationRecognizer_ManipulationStartedEvent
中对Gaze凝视的对象发送的是PerformManipulationStart
函数; - 在
ManipulationRecognizer_ManipulationUpdatedEvent
中对Gaze凝视的对象发送的是PerformManipulationUpdate
函数;
Holographic Action 对象函数动作
**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;
}
}
}