Hololens开发笔记之Gesture手势识别(Manipulation手势控制物体平移)
Manipulation gesture:保持点击手势,在3D世界中绝对运动
当你想要全息图像1:1响应用户手部移动时,操纵手势能被用于移动、缩放或旋转全息图像。如此的一个用处是使得用户可以在世界中绘制图像或作画。使用所有的手势时,操纵手势的初始目标应该通过凝视来选中。一旦点击手势开始,通过手部移动的任何对对象的操作都能够被处理,在用户操作全息图像时,从而使得用户得以自由地四处张望。
1、修改HandsManager.cs,添加InteractionManager.SourcePressed,InteractionManager.SourceReleased处理函数,用于识别物体被点击和被释放的事件
HandsManager.cs完整代码如下:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Generic; using UnityEngine; using UnityEngine.VR.WSA.Input; namespace HoloToolkit.Unity { /// <summary> /// HandsManager determines if the hand is currently detected or not. /// </summary> public partial class HandsManager : Singleton<HandsManager> { /// <summary> /// HandDetected tracks the hand detected state. /// Returns true if the list of tracked hands is not empty. /// </summary> public bool HandDetected { get { return trackedHands.Count > 0; } } private HashSet<uint> trackedHands = new HashSet<uint>(); public GameObject FocusedGameObject { get; private set; } void Awake() { //识别到来源 InteractionManager.SourceDetected += InteractionManager_SourceDetected; //来源丢失 InteractionManager.SourceLost += InteractionManager_SourceLost; //来源被按下 InteractionManager.SourcePressed += InteractionManager_SourcePressed; //被释放 InteractionManager.SourceReleased += InteractionManager_SourceReleased; FocusedGameObject = null; } private void InteractionManager_SourceDetected(InteractionSourceState state) { // Check to see that the source is a hand. if (state.source.kind != InteractionSourceKind.Hand) { return; } trackedHands.Add(state.source.id); } private void InteractionManager_SourceLost(InteractionSourceState state) { // Check to see that the source is a hand. if (state.source.kind != InteractionSourceKind.Hand) { return; } if (trackedHands.Contains(state.source.id)) { trackedHands.Remove(state.source.id); } FocusedGameObject = null; } //手势释放时,将被关注的物体置空 private void InteractionManager_SourceReleased(InteractionSourceState state) { FocusedGameObject = null; } //识别到手指按下时,将凝视射线关注的物体置为当前手势操作的对象 private void InteractionManager_SourcePressed(InteractionSourceState state) { if (GazeManager.Instance.FocusedObject != null) { FocusedGameObject = GazeManager.Instance.FocusedObject; } } void OnDestroy() { InteractionManager.SourceDetected -= InteractionManager_SourceDetected; InteractionManager.SourceLost -= InteractionManager_SourceLost; InteractionManager.SourceReleased -= InteractionManager_SourceReleased; InteractionManager.SourcePressed -= InteractionManager_SourcePressed; } } }
2、修改GestureManager.cs,订阅Manipulation gesture事件
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System; using UnityEngine; using UnityEngine.VR.WSA.Input; namespace HoloToolkit.Unity { /// <summary> /// GestureManager creates a gesture recognizer and signs up for a tap gesture. /// When a tap gesture is detected, GestureManager uses GazeManager to find the game object. /// GestureManager then sends a message to that game object. /// </summary> [RequireComponent(typeof(GazeManager))] public partial class GestureManager : Singleton<GestureManager> { /// <summary> /// Key to press in the editor to select the currently gazed hologram /// </summary> public KeyCode EditorSelectKey = KeyCode.Space; /// <summary> /// To select even when a hologram is not being gazed at, /// set the override focused object. /// If its null, then the gazed at object will be selected. /// </summary> public GameObject OverrideFocusedObject { get; set; } public bool IsManipulating { get; private set; } public Vector3 ManipulationPosition { get; private set; } /// <summary> /// Gets the currently focused object, or null if none. /// </summary> public GameObject FocusedObject { get { return focusedObject; } } private GestureRecognizer gestureRecognizer; private GameObject focusedObject; void Start() { // Create a new GestureRecognizer. Sign up for tapped events. gestureRecognizer = new GestureRecognizer(); gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap | GestureSettings.DoubleTap | GestureSettings.ManipulationTranslate); gestureRecognizer.TappedEvent += GestureRecognizer_TappedEvent; //订阅Manipulation gesture事件 gestureRecognizer.ManipulationStartedEvent += GestureRecognizer_ManipulationStartedEvent; gestureRecognizer.ManipulationUpdatedEvent += GestureRecognizer_ManipulationUpdatedEvent; gestureRecognizer.ManipulationCompletedEvent += GestureRecognizer_ManipulationCompletedEvent; gestureRecognizer.ManipulationCanceledEvent += GestureRecognizer_ManipulationCanceledEvent; // Start looking for gestures. gestureRecognizer.StartCapturingGestures(); } private void GestureRecognizer_ManipulationStartedEvent(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headRay) { //当被关注的对象非空时,设置初始位置 if (HandsManager.Instance.FocusedGameObject != null) { IsManipulating = true; ManipulationPosition = cumulativeDelta; HandsManager.Instance.FocusedGameObject.SendMessageUpwards("PerformManipulationStart", cumulativeDelta); } } private void GestureRecognizer_ManipulationUpdatedEvent(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headRay) { //当被关注的对象非空时,更新新的位置 if (HandsManager.Instance.FocusedGameObject != null) { IsManipulating = true; ManipulationPosition = cumulativeDelta; HandsManager.Instance.FocusedGameObject.SendMessageUpwards("PerformManipulationUpdate", cumulativeDelta); } } private void GestureRecognizer_ManipulationCompletedEvent(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headRay) { IsManipulating = false; } private void GestureRecognizer_ManipulationCanceledEvent(InteractionSourceKind source, Vector3 cumulativeDelta, Ray headRay) { IsManipulating = false; } private void OnTap() { if (focusedObject != null) { focusedObject.SendMessage("OnTap"); } } private void OnDoubleTap() { if (focusedObject != null) { focusedObject.SendMessage("OnDoubleTap"); } } private void GestureRecognizer_TappedEvent(InteractionSourceKind source, int tapCount, Ray headRay) { if (tapCount == 1) { OnTap(); } else { OnDoubleTap(); } } void LateUpdate() { GameObject oldFocusedObject = focusedObject; if (GazeManager.Instance.Hit && OverrideFocusedObject == null && GazeManager.Instance.HitInfo.collider != null) { // If gaze hits a hologram, set the focused object to that game object. // Also if the caller has not decided to override the focused object. focusedObject = GazeManager.Instance.HitInfo.collider.gameObject; } else { // If our gaze doesn't hit a hologram, set the focused object to null or override focused object. focusedObject = OverrideFocusedObject; } //if (focusedObject != oldFocusedObject) //{ // // If the currently focused object doesn't match the old focused object, cancel the current gesture. // // Start looking for new gestures. This is to prevent applying gestures from one hologram to another. // gestureRecognizer.CancelGestures(); // gestureRecognizer.StartCapturingGestures(); //} } void OnDestroy() { gestureRecognizer.StopCapturingGestures(); //取消订阅 gestureRecognizer.TappedEvent -= GestureRecognizer_TappedEvent; gestureRecognizer.ManipulationStartedEvent -= GestureRecognizer_ManipulationStartedEvent; gestureRecognizer.ManipulationUpdatedEvent -= GestureRecognizer_ManipulationUpdatedEvent; gestureRecognizer.ManipulationCompletedEvent -= GestureRecognizer_ManipulationCompletedEvent; gestureRecognizer.ManipulationCanceledEvent -= GestureRecognizer_ManipulationCanceledEvent; } } }
3、添加ManipulationTranslate脚本,计算相对位移,然后进行更新物体的新的位置。
using UnityEngine; using System.Collections; using HoloToolkit.Unity; public class ManipulationTranslate: MonoBehaviour { private Vector3 manipulationPreviousPosition; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } void PerformManipulationStart(Vector3 position) { //设置初始位置 manipulationPreviousPosition = position; } void PerformManipulationUpdate(Vector3 position) { if (GestureManager.Instance.IsManipulating) { //计算相对位移,然后更新物体的位置 Vector3 moveVector = Vector3.zero; moveVector = position - manipulationPreviousPosition; manipulationPreviousPosition = position; transform.position += 2f * moveVector; } }
4、运行测试
将凝视射线投射到对象上,举起右手使食指和拇指碰触在一起,然后进行左右移动,可以看到物体的位置将移动。