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;
}
}
}
}