本文實現當使用者手出現在Hololens視野范圍內時,跟蹤手並給出反饋的效果。
1、在Manager上添加HandsManager腳本組件,用於追蹤識別手
HandsManager.cs如下(直接使用HoloTooKit中腳本)
// 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.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>(); void Awake() { //識別到來源 InteractionManager.SourceDetected += InteractionManager_SourceDetected; //來源丟失 InteractionManager.SourceLost += InteractionManager_SourceLost; } private void InteractionManager_SourceDetected(InteractionSourceState state) { // 檢測來源是否為手,如果是手則加入跟蹤集合 if (state.source.kind != InteractionSourceKind.Hand) { return; } trackedHands.Add(state.source.id); } private void InteractionManager_SourceLost(InteractionSourceState state) { // 檢測丟失的來源是否為手,如果是手則從跟蹤集合中去除 if (state.source.kind != InteractionSourceKind.Hand) { return; } if (trackedHands.Contains(state.source.id)) { trackedHands.Remove(state.source.id); } } void OnDestroy() { InteractionManager.SourceDetected -= InteractionManager_SourceDetected; InteractionManager.SourceLost -= InteractionManager_SourceLost; } } }
該腳本中使用到了底層API Interaction Input
底層API運行獲得輸入來源的更多詳細信息,例如它在世界中的位置和速度。
如何處理底層交互事件
使用底層交互是很容易的:
1) 注冊InteractionManager事件
2) 處理事件
停止它也很容易:
1) 取消注冊事件
處理底層交互事件
一旦注冊了底層交互事件,在事件發生時你就可以得到回調。你可以使用獲取到的時間信息來處理應用行為。
void InteractionManager_SourcePressed(InteractionSourceState state) { // state變量里包含以下信息: // 當前凝視射線信息 // 來源是否被點擊 // 位置、速度之類的屬性 // 來源id和來源類型 ( hand, voice, controller或其他) }
如何停止交互事件
當你不再想要關注一些事件后,只需要取消時間注冊即可。
InteractionManager.SourcePressed -= InteractionManager_SourcePressed;
輸入源變化事件
這些事件描述了輸入源的當前狀態:
1) detected( 即將激活)
2) lost( 即將取消激活)
3) updates( 移動或者一些狀態在變化)
4) is pressed( 點擊、按鈕按下或者語音選中)
5) is released( 點擊結束,按鈕松開,語音選中結束)
輸入源狀態
每個事件都會有一個InteractionSourceState參數,這個參數代表了實時輸入源狀態:
1) 是否是點擊狀態
2) InteractionSourceProperties包含了輸入源位置信息 InteractionSourceLocation,能夠獲得當前輸入源位置和速度信息
3) 凝視射線信息,用於判斷事件發生時用戶是否在注視目標
4) 來源類型信息,包括hand、voice、controller或者其他類型
2、在Cursor下新建Empty對象,並重命名為CursorBillboard,並添加Billboard腳本組件
Billboard腳本如下(可以直接在HoloToolKit中找到)
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using UnityEngine; namespace HoloToolkit.Unity { public enum PivotAxis { // Rotate about all axes. Free, // Rotate about an individual axis. X, Y } /// <summary> /// The Billboard class implements the behaviors needed to keep a GameObject /// oriented towards the user. /// </summary> public class Billboard : MonoBehaviour { /// <summary> /// The axis about which the object will rotate. /// </summary> [Tooltip("Specifies the axis about which the object will rotate (Free rotates about both X and Y).")] public PivotAxis PivotAxis = PivotAxis.Free; /// <summary> /// Overrides the cached value of the GameObject's default rotation. /// </summary> public Quaternion DefaultRotation { get; private set; } private void Awake() { // Cache the GameObject's default rotation. DefaultRotation = gameObject.transform.rotation; } /// <summary> /// Keeps the object facing the camera. /// </summary> private void Update() { // Get a Vector that points from the Camera to the target. Vector3 forward; Vector3 up; // Adjust for the pivot axis. We need a forward and an up for use with Quaternion.LookRotation switch (PivotAxis) { // If we're fixing one axis, then we're projecting the camera's forward vector onto // the plane defined by the fixed axis and using that as the new forward. case PivotAxis.X: Vector3 right = transform.right; // Fixed right forward = Vector3.ProjectOnPlane(Camera.main.transform.forward, right).normalized; up = Vector3.Cross(forward, right); // Compute the up vector break; case PivotAxis.Y: up = transform.up; // Fixed up forward = Vector3.ProjectOnPlane(Camera.main.transform.forward, up).normalized; break; // If the axes are free then we're simply aligning the forward and up vectors // of the object with those of the camera. case PivotAxis.Free: default: forward = Camera.main.transform.forward; up = Camera.main.transform.up; break; } // Calculate and apply the rotation required to reorient the object transform.rotation = Quaternion.LookRotation(forward, up); } } }
3、在Cursor上添加CursorFeedback腳本組件
1) 在HoloToolkit -> Input -> Prefabs中找到HandDetectedFeedback Prefab 並拖到CursorFeedback的hand detected asset上
2) 將剛才創建的CursorBillboard拖到CursorFeedback的Feedback Parent上
CursorFeedback腳本如下((可以直接在HoloToolKit中找到))
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using UnityEngine; namespace HoloToolkit.Unity { /// <summary> /// CursorFeedback class takes GameObjects to give cursor feedback /// to users based on different states. /// </summary> public class CursorFeedback : MonoBehaviour { [Tooltip("Drag a prefab object to display when a hand is detected.")] public GameObject HandDetectedAsset; private GameObject handDetectedGameObject; [Tooltip("Drag a prefab object to parent the feedback assets.")] public GameObject FeedbackParent; void Awake() { if (HandDetectedAsset != null) { handDetectedGameObject = InstantiatePrefab(HandDetectedAsset); } else { Debug.LogError("Missing a required game object asset. Check HandDetectedAsset is not null in editor."); } } private GameObject InstantiatePrefab(GameObject inputPrefab) { GameObject instantiatedPrefab = null; if (inputPrefab != null && FeedbackParent != null) { instantiatedPrefab = GameObject.Instantiate(inputPrefab); // Assign parent to be the FeedbackParent // so that feedback assets move and rotate with this parent. instantiatedPrefab.transform.parent = FeedbackParent.transform; // Set starting state of the prefab's GameObject to be inactive. instantiatedPrefab.gameObject.SetActive(false); } else { Debug.LogError("Missing a required game object asset. Check FeedbackParent is not null in editor."); } return instantiatedPrefab; } void Update() { UpdateHandDetectedState(); } private void UpdateHandDetectedState() { if (handDetectedGameObject == null) { return; } handDetectedGameObject.SetActive(HandsManager.Instance.HandDetected); } } }
4、運行測試
當手出現在Hololens視野中時,手被檢測到,在凝視射線處出現一個藍色的小手(Hololens模擬器中需要處於hold狀態才會出現藍色小手,真機上只要手舉起就可以)