using System.Collections; using System.Collections.Generic; using UnityEngine; using Ximmerse.XR.Utils; namespace Ximmerse.XR.InputSystems { /// /// Virtual hand renderer, for hand tracking. /// public class VirtualHandRenderer : MonoBehaviour { /// /// If true, colliders are disabled when start the behaviour. /// public bool DisableCollidersAtStartup = true; /// /// The game object prefab of palm. /// public GameObject palm; /// /// Joints of thumb finger /// public GameObject[] thumbJoints; public GameObject[] thumbConnections; /// /// Joints of index finger /// public GameObject[] indexJoints; public GameObject[] indexConnections; /// /// Joints of middle finger /// public GameObject[] middleJoints; public GameObject[] middleConnections; /// /// Joints of ring finger /// public GameObject[] ringJoints; public GameObject[] ringConnections; /// /// Joints of little finger /// public GameObject[] littleJoints; public GameObject[] littleConnections; /// /// Deactivate model time valve. /// const float kDeactiveTimeValve = 0.10f; float deactiveTimeCounter = 0; private bool isHandModelActive = false; Collider[] subColliders = null; private void Awake() { subColliders = GetComponentsInChildren(true); } private void Start() { EnableHandModel(false); if(DisableCollidersAtStartup) { this.EnableSubColliders(false); } } // Update is called once per frame void LateUpdate() { if (HandTracking.IsHandTrackingEnable) { if (isHandModelActive) { UpdateHandTransforms(); } var trackedInfo = HandTracking.HandTrackingInfo; if (!trackedInfo.IsValid) { deactiveTimeCounter += Time.deltaTime; if (deactiveTimeCounter >= kDeactiveTimeValve && isHandModelActive) { EnableHandModel(false); } } else { if (!isHandModelActive) { EnableHandModel(true); } deactiveTimeCounter = 0;//reset time counter on valid hand case. } } } /// /// update transforms of each finger's joint and connection. /// private void UpdateHandTransforms() { var trackedInfo = HandTracking.HandTrackingInfo; this.palm.transform.SetPositionAndRotation(trackedInfo.PalmPosition, trackedInfo.PalmRotation); this.palm.transform.localScale = trackedInfo.PalmScale; UpdateFingerJoints(this.thumbJoints, this.thumbConnections, trackedInfo.ThumbFinger); UpdateFingerJoints(this.indexJoints, this.indexConnections, trackedInfo.IndexFinger); UpdateFingerJoints(this.middleJoints, this.middleConnections, trackedInfo.MiddleFinger); UpdateFingerJoints(this.ringJoints, this.ringConnections, trackedInfo.RingFinger); UpdateFingerJoints(this.littleJoints, this.littleConnections, trackedInfo.LittleFinger); } private void UpdateFingerJoints(GameObject[] joints, GameObject[] connections, RawFingerTrackingInfo fingerTrackInfo) { for (int i = 0, iMax = joints.Length; i < iMax; i++) { joints[i].transform.position = fingerTrackInfo.Positions[i]; } for (int i = 0, iMax = connections.Length; i < iMax; i++) { connections[i].transform.position = (fingerTrackInfo.Positions[i + 1] + fingerTrackInfo.Positions[i]) / 2; connections[i].transform.up = (fingerTrackInfo.Positions[i + 1] - fingerTrackInfo.Positions[i]).normalized; } } /// /// Activate / Deactivate hand model /// /// void EnableHandModel(bool enabled) { isHandModelActive = enabled; palm.gameObject.SetActive(enabled); foreach (var g in thumbJoints) { g.gameObject.SetActive(enabled); } foreach (var g in indexJoints) { g.gameObject.SetActive(enabled); } foreach (var g in middleJoints) { g.gameObject.SetActive(enabled); } foreach (var g in ringJoints) { g.gameObject.SetActive(enabled); } foreach (var g in littleJoints) { g.gameObject.SetActive(enabled); } foreach (var g in thumbConnections) { g.gameObject.SetActive(enabled); } foreach (var g in indexConnections) { g.gameObject.SetActive(enabled); } foreach (var g in middleConnections) { g.gameObject.SetActive(enabled); } foreach (var g in ringConnections) { g.gameObject.SetActive(enabled); } foreach (var g in littleConnections) { g.gameObject.SetActive(enabled); } } /// /// Enable/disable sub colliders /// public void EnableSubColliders(bool enable) { foreach(var c in subColliders) { c.enabled = enable; } } } }