Hololens开发手记 - 移动全息对象(Manipulation)

本文将以官方案例来说明如何实现移动全息对象操作(211 - chapter4)。此案例主要涉及到了语音、手势识别。

实现思路:

  • 通过添加的关键字来初始化KeywordRecognizer;
  • 创建一个GestureRecognizer用于实现Manipulation Holographic;
  • 通过语音识别调用对应的函数操作实现选择不同的GestureRecognizer;
  • 通过不同的手势识别操作来对应地向Gaze射线凝视的物体发送消息实现操作;

以MSDN上官网的demo为例:

Hololens开发手记 - 移动全息对象(Manipulation)_第1张图片
Paste_Image.png

首先可以创建一个空物体来管理相关的Gaze、Hand、Gesture相关操作。在这里我们将对全息对象的管理脚本(也就是包含语音操作命令)也挂载在此空物体Manager上。

语音输入 Voice Command


  1. 声明一个KeywordRecognizer ;
  2. 声明一个Dictionary keywordCollection用于保存关键字和对应的关键字函数;
  3. 在Start()函数中进行添加语音关键字;
  4. 在Start()函数中由添加的关键字字典keywordCollection进行对KeywordRecognizer 初始化并开始关键字识别;
  5. 对关键字对应的操作函数进行编写。此案例中为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
{
    // KeywordRecognizer object.
    KeywordRecognizer keywordRecognizer;

    // Defines which function to call when a keyword is recognized.
    delegate void KeywordAction(PhraseRecognizedEventArgs args);
    Dictionary keywordCollection;

    void Start()
    {
        keywordCollection = new Dictionary();

        // 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集成手势识别:

  1. 创建GestureRecognizer实例
  2. 注册指定的手势类型
  3. 订阅手势事件
  4. 开始手势识别
**GestureManager.cs**

using HoloToolkit;
using UnityEngine;
using UnityEngine.VR.WSA.Input;

public class GestureManager : Singleton
{
    // 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;
    }

    /// 
    /// Transition to a new GestureRecognizer.
    /// 
    /// The GestureRecognizer to transition to.
    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;

/// 
/// GestureAction performs custom actions based on 
/// which gesture is being performed.
/// 
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;
        }
    }
}

你可能感兴趣的:(Hololens开发手记 - 移动全息对象(Manipulation))