version 2.5.1

This commit is contained in:
Sean Lu
2025-01-08 10:28:35 +08:00
parent 2bfa2ad4c7
commit ae66f9c2fe
91 changed files with 7009 additions and 2005 deletions

View File

@@ -699,6 +699,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 4806409459047702211}
- component: {fileID: 5568897672767345397}
- component: {fileID: 1039589470112983849}
- component: {fileID: 1039589470112983840}
- component: {fileID: 1039589470112983852}
@@ -725,6 +726,19 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5568897672767345397
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4806409459047702212}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Handedness: 1
--- !u!114 &1039589470112983849
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -858,6 +858,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 7152668487518777764}
- component: {fileID: 7057365311429264906}
- component: {fileID: 3431167848623168894}
- component: {fileID: 3431167848623168881}
- component: {fileID: 3431167848623168882}
@@ -884,6 +885,19 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7057365311429264906
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7152668487518777765}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Handedness: 0
--- !u!114 &3431167848623168894
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -8,12 +8,13 @@
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System.Collections.Generic;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
using System.Linq;
using UnityEngine.InputSystem;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
@@ -129,6 +130,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private HandGrabInteractable candidate = null;
private Pose wristPose = Pose.identity;
private Quaternion[] fingerJointRotation = new Quaternion[jointsPathMapping.Count];
private bool isNewInputSystem = false;
#region MonoBehaviours
@@ -156,6 +158,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
sb.Append("However, you still can record grab pose if you use direct preview mode.");
WARNING(sb);
}
isNewInputSystem = Keyboard.current != null;
}
private void OnDisable()
@@ -199,7 +202,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
}
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
if (IsEnterPressed())
{
FindNearInteractable();
SavePoseWithCandidate();
@@ -326,6 +329,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
return updated;
}
private bool IsEnterPressed()
{
if (isNewInputSystem)
{
return (Keyboard.current.enterKey?.wasPressedThisFrame ?? false) ||
(Keyboard.current.numpadEnterKey?.wasPressedThisFrame ?? false);
}
else
{
return Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter);
}
}
/// <summary>
/// Finds the nearest interactable object to the hand.
/// </summary>

View File

@@ -8,7 +8,6 @@
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
@@ -87,8 +86,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
[SerializeField]
private IOneHandContraintMovement m_OneHandContraintMovement;
public IOneHandContraintMovement oneHandContraintMovement { get { return m_OneHandContraintMovement; } set { m_OneHandContraintMovement = value; } }
public bool isContraint => m_OneHandContraintMovement != null;
public IOneHandContraintMovement oneHandContraintMovement { get { return m_OneHandContraintMovement; } set { m_OneHandContraintMovement = value; } }
public bool isContraint => m_OneHandContraintMovement != null;
#pragma warning disable
[SerializeField]
@@ -183,8 +182,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
if (!isGrabbable || isGrabbed) { return 0; }
Vector3 closestPoint = GetClosestPoint(grabberPos);
float distacne = Vector3.Distance(grabberPos, closestPoint);
return distacne > grabDistance ? 0 : 1 - (distacne / grabDistance);
float distanceSqr = (grabberPos - closestPoint).sqrMagnitude;
float grabDistSqr = grabDistance * grabDistance;
return distanceSqr > grabDistSqr ? 0 : 1 - (distanceSqr / grabDistSqr);
}
/// <summary>
@@ -263,35 +263,41 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Vector3 GetClosestPoint(Vector3 sourcePos)
{
Vector3 closestPoint = Vector3.zero;
float shortDistance = float.MaxValue;
float shortDistanceSqr = float.MaxValue;
for (int i = 0; i < allColliders.Count; i++)
{
Collider collider = allColliders[i];
Vector3 closePoint = collider.ClosestPointOnBounds(sourcePos);
float distance = Vector3.Distance(sourcePos, closePoint);
float distanceSqr = (sourcePos - closePoint).sqrMagnitude;
if (distanceSqr < 0.001f)
{
return closePoint;
}
if (collider.bounds.Contains(closePoint))
{
Vector3 direction = closePoint - sourcePos;
direction.Normalize();
int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, distance);
int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, Mathf.Sqrt(distanceSqr));
for (int j = 0; j < hitCount; j++)
{
RaycastHit hit = hitResults[j];
if (hit.collider == collider)
{
float hitDistance = Vector3.Distance(sourcePos, hit.point);
if (distance > hitDistance)
float hitDistanceSqr = (sourcePos - hit.point).sqrMagnitude;
if (distanceSqr > hitDistanceSqr)
{
distance = hitDistance;
distanceSqr = hitDistanceSqr;
closePoint = hit.point;
}
}
}
}
if (shortDistance > distance)
if (shortDistanceSqr > distanceSqr)
{
shortDistance = distance;
shortDistanceSqr = distanceSqr;
closestPoint = closePoint;
}
}
@@ -361,9 +367,12 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="index">The index of the indicator to show.</param>
private void ShowIndicatorByIndex(int index)
{
foreach (var grabPose in m_GrabPoses)
for (int i = 0; i < m_GrabPoses.Count; i++)
{
grabPose.indicator.SetActive(false);
if (index != i)
{
m_GrabPoses[i].indicator.SetActive(false);
}
}
if (index >= 0 && index < m_GrabPoses.Count &&
m_GrabPoses[index].indicator.enableIndicator)
@@ -379,9 +388,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="isLeft">Whether the hand side is left.</param>
private void ShowAllIndicator(bool isLeft)
{
foreach (var grabPose in m_GrabPoses)
for (int i = 0; i < m_GrabPoses.Count; i++)
{
grabPose.indicator.SetActive(false);
m_GrabPoses[i].indicator.SetActive(false);
}
foreach (var grabPose in m_GrabPoses)
{

View File

@@ -8,7 +8,6 @@
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
@@ -79,6 +78,13 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Pose wristPose = Pose.identity;
private Vector3[] fingerTipPosition = new Vector3[(int)FingerId.Count];
private const int kMaxCacheSize = 100;
private int lastBufferCount = 0;
private Collider[] colliderBuffer = new Collider[50];
private HandGrabInteractable[] grabbableBuffer = new HandGrabInteractable[50];
private LinkedList<Collider> lruList = new LinkedList<Collider>();
private Dictionary<Collider, LinkedListNode<Collider>> unusedColliders = new Dictionary<Collider, LinkedListNode<Collider>>();
#region MonoBehaviour
private void Awake()
{
@@ -159,7 +165,6 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// </summary>
private void FindCandidate()
{
currentCandidate = null;
float distanceScore = float.MinValue;
if (GetClosestGrabbable(m_GrabDistance, out HandGrabInteractable grabbable, out float score) && score > distanceScore)
{
@@ -189,28 +194,47 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
grabbable = null;
maxScore = 0f;
Collider[] nearColliders = Physics.OverlapSphere(wristPose.position, 0.5f);
List<HandGrabInteractable> nearHandGrabInteractables = new List<HandGrabInteractable>();
for (int i = 0; i < nearColliders.Length; i++)
for (int i = 0; i < lastBufferCount; i++)
{
HandGrabInteractable interactable = nearColliders[i].GetComponentInParent<HandGrabInteractable>();
if (interactable && !nearHandGrabInteractables.Contains(interactable))
{
nearHandGrabInteractables.Add(interactable);
continue;
}
interactable = nearColliders[i].GetComponentInChildren<HandGrabInteractable>();
if (interactable && !nearHandGrabInteractables.Contains(interactable))
{
nearHandGrabInteractables.Add(interactable);
continue;
}
HandGrabInteractable interactable = grabbableBuffer[i];
interactable.ShowIndicator(false, this);
}
for (int i = 0; i < nearHandGrabInteractables.Count; i++)
int colliderCount = Physics.OverlapSphereNonAlloc(wristPose.position, grabDistance * 5, colliderBuffer);
int interactableCount = 0;
for (int i = 0; i < colliderCount; i++)
{
HandGrabInteractable interactable = nearHandGrabInteractables[i];
interactable.ShowIndicator(false, this);
Collider collider = colliderBuffer[i];
if (unusedColliders.TryGetValue(collider, out _)) { continue; }
HandGrabInteractable interactable = collider.GetComponentInParent<HandGrabInteractable>()
?? collider.GetComponentInChildren<HandGrabInteractable>();
if (interactable != null)
{
bool isUnique = true;
for (int j = 0; j < interactableCount; j++)
{
if (grabbableBuffer[j] == interactable)
{
isUnique = false;
break;
}
}
if (isUnique)
{
grabbableBuffer[interactableCount++] = interactable;
}
}
else
{
AddUnusedColliders(collider);
}
}
lastBufferCount = interactableCount;
for (int i = 0; i < interactableCount; i++)
{
HandGrabInteractable interactable = grabbableBuffer[i];
for (int j = 0; j < fingerTipPosition.Length; j++)
{
float distanceScore = interactable.CalculateDistanceScore(fingerTipPosition[j], grabDistance);
@@ -279,5 +303,18 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
m_Grabbable.UpdatePositionAndRotation(wristPose);
}
private void AddUnusedColliders(Collider collider)
{
if (lruList.Count >= kMaxCacheSize)
{
var oldest = lruList.First;
unusedColliders.Remove(oldest.Value);
lruList.RemoveFirst();
}
var node = lruList.AddLast(collider);
unusedColliders[collider] = node;
}
}
}

View File

@@ -11,7 +11,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
@@ -85,7 +84,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Quaternion lastRotation;
private bool isInit = false;
private bool isTracked = true;
private List<Vector3> collisionDirections = new List<Vector3>();
private const int k_MaxCollisionCount = 100;
private readonly ContactPoint[] contactPointsBuffer = new ContactPoint[k_MaxCollisionCount];
private readonly Vector3[] collisionsDirection = new Vector3[k_MaxCollisionCount];
private readonly object collisionLock = new object();
private int currentCollisionCount = 0;
private bool isGrabbing = false;
#region MonoBehaviour
@@ -163,7 +166,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
if (isGrabbing)
{
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero;
rootJoint.localPosition = lastRootPos;
rootJoint.localRotation = lastRotation;
@@ -175,7 +182,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
}
#endregion
#endregion
private IEnumerator WaitForInit()
{
@@ -232,33 +239,41 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
Vector3 vel = (lastRootPos - rootJoint.position) / Time.deltaTime;
if (IsValidVelocity(vel))
{
if (collisionDirections.Count > 0)
lock (collisionLock)
{
float minAngle = float.MaxValue;
Vector3 closestDirection = Vector3.zero;
foreach (Vector3 direction in collisionDirections.ToList())
if (currentCollisionCount > 0)
{
float angle = Mathf.Abs(Vector3.Angle(direction, vel));
if (angle < minAngle)
{
minAngle = angle;
closestDirection = direction;
}
}
collisionDirections.Clear();
float minAngle = float.MaxValue;
Vector3 closestDirection = Vector3.zero;
Vector3 adjustedDirection = closestDirection;
if (Vector3.Dot(vel, closestDirection) > 0)
{
adjustedDirection *= -1f;
}
vel = Vector3.ProjectOnPlane(vel, adjustedDirection);
if (vel.magnitude > 1)
{
vel.Normalize();
for (int i = 0; i < currentCollisionCount; i++)
{
Vector3 direction = collisionsDirection[i];
float angle = Mathf.Abs(Vector3.Angle(direction, vel));
if (angle < minAngle)
{
minAngle = angle;
closestDirection = direction;
}
}
Vector3 adjustedDirection = closestDirection;
if (Vector3.Dot(vel, closestDirection) > 0)
{
adjustedDirection *= -1f;
}
vel = Vector3.ProjectOnPlane(vel, adjustedDirection);
if (vel.magnitude > 1)
{
vel.Normalize();
}
currentCollisionCount = 0;
}
}
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = vel;
#else
rootJointRigidbody.velocity = vel;
#endif
}
}
@@ -287,7 +302,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
&& !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z);
}
#region Event CallBack
#region Event CallBack
/// <summary>
/// When tracking state changing, reset the pose and enable/disable collider.
@@ -299,7 +314,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
lastRootPos = Vector3.zero;
lastRotation = Quaternion.identity;
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero;
}
foreach (JointCollider jointCollider in jointsCollider)
@@ -355,17 +374,21 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
case JointCollider.CollisionState.Stay:
if (collision.contactCount > 0 && (collision.rigidbody == null || collision.rigidbody.isKinematic))
{
ContactPoint[] contactPoints = new ContactPoint[collision.contactCount];
collision.GetContacts(contactPoints);
foreach (ContactPoint contactPoint in contactPoints)
lock (collisionLock)
{
collisionDirections.Add(contactPoint.normal * -1f);
currentCollisionCount = Mathf.Min(contactPointsBuffer.Length, collision.contactCount);
collision.GetContacts(contactPointsBuffer);
for (int i = 0; i < currentCollisionCount; i++)
{
collisionsDirection[i] = contactPointsBuffer[i].normal * -1f;
}
}
}
break;
}
}
#endregion
#endregion
}
}

View File

@@ -635,6 +635,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
},
};
// palm, wrist, thumb, index, middle, ring, pinky
private static readonly int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
public bool valid = false;
public bool isTracked = false;
@@ -771,14 +773,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
group = 0;
index = jointId;
// palm, wrist, thumb, index, middle, ring, pinky
int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
while (index > fingerGroup[group])
for (int i = 0; i < fingerGroup.Length; i++)
{
index -= fingerGroup[group];
group += 1;
if (index <= fingerGroup[i])
{
group = i;
index -= 1; // Adjust to 0-based index
return;
}
index -= fingerGroup[i];
}
index -= 1;
}
}
@@ -848,32 +852,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="isLeft">True if the hand is left; otherwise, false.</param>
private static void GetFingerData(FingerId id, ref FingerData finger, bool isLeft)
{
JointType[] jointTypes = { };
switch (id)
{
case FingerId.Thumb: jointTypes = s_ThumbJoints; break;
case FingerId.Index: jointTypes = s_IndexJoints; break;
case FingerId.Middle: jointTypes = s_MiddleJoints; break;
case FingerId.Ring: jointTypes = s_RingJoints; break;
case FingerId.Pinky: jointTypes = s_PinkyJoints; break;
default: return;
}
JointType[] jointTypes = GetJointTypes(id);
if (jointTypes == null) return;
float deltaTime = Time.deltaTime;
Vector3 parentVel = Vector3.zero;
for (int i = 0; i < jointTypes.Length; i++)
{
Vector3 parentVel = i == 0 ? Vector3.zero : finger.joints[i - 1].velocity;
JointData lastJoint = finger.joints[i];
GetJointData(jointTypes[i], ref finger.joints[i], isLeft);
ref JointData joint = ref finger.joints[i];
Vector3 lastPosition = joint.position;
DataWrapper.GetJointPose(jointTypes[i], ref joint.position, ref joint.rotation, isLeft);
joint.velocity = (joint.position - lastPosition) / deltaTime;
//As the velocity of child node should not be lower than the parent node.
//Add the current parent node's velocity multiplied by time to the last position of child node, obtaining the new simulated position.
if (parentVel.magnitude > finger.joints[i].velocity.magnitude)
if (parentVel.magnitude > joint.velocity.magnitude)
{
lastJoint.position += parentVel * Time.deltaTime;
finger.joints[i] = lastJoint;
joint.position += parentVel * deltaTime;
}
parentVel = joint.velocity;
}
// Since the thumb does not have joint3, it is replaced by joint2.
if (id == FingerId.Thumb)
{
finger.joints[(int)JointId.Tip] = finger.joint3;
@@ -885,6 +886,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
}
private static JointType[] GetJointTypes(FingerId id)
{
return id switch
{
FingerId.Thumb => s_ThumbJoints,
FingerId.Index => s_IndexJoints,
FingerId.Middle => s_MiddleJoints,
FingerId.Ring => s_RingJoints,
FingerId.Pinky => s_PinkyJoints,
_ => null
};
}
/// <summary>
/// Update the data for the left or right hand.
/// </summary>
@@ -1067,16 +1081,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
Vector3 thumbTip = thumbData.tip.position;
Vector3 thumbJoint2 = thumbData.joint2.position;
Vector3 thumbJoint1 = thumbData.joint1.position;
Vector3[] fingerPos = { fingerData.tip.position,
fingerData.joint3.position,
fingerData.joint2.position};
float distance = float.PositiveInfinity;
for (int i = 0; i < fingerPos.Length; i++)
{
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbJoint2, thumbJoint1));
}
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbJoint2, thumbJoint1));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbJoint2, thumbJoint1));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbJoint2, thumbJoint1));
return distance;
}
@@ -1732,9 +1746,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="enable">True to enable the indicator, false to deactivate it.</param>
public void SetActive(bool enable)
{
if (target != null)
if (target)
{
target.SetActive(enable);
if (enable)
{
target.transform.localScale = Vector3.one;
}
else
{
target.transform.localScale = Vector3.zero;
}
}
}

View File

@@ -7,7 +7,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
[SerializeField]
private HandMeshManager m_HandMesh;
private bool keepUpdate = false;
protected override void OnEnable()
@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
protected override void OnDisable()
{
base.OnDisable();
if (keepUpdate)
{
keepUpdate = false;
StopCoroutine(UpdatePose());
}
keepUpdate = false;
}
public void SetHandMeshRenderer(HandMeshManager handMeshRenderer)
@@ -44,39 +40,32 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
yield return new WaitUntil(() => m_Initialized);
base.OnEnable();
if (!keepUpdate)
{
keepUpdate = true;
StartCoroutine(UpdatePose());
}
keepUpdate = true;
}
private IEnumerator UpdatePose()
private void Update()
{
while (keepUpdate)
if (!keepUpdate) { return; }
HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT);
m_IsTracked = handPose.IsTracked();
if (!m_IsTracked) { return; }
for (int i = 0; i < poseCount; i++)
{
yield return new WaitForFixedUpdate();
HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT);
m_IsTracked = handPose.IsTracked();
for (int i = 0; i < poseCount; i++)
if (m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 position, out Quaternion rotation) &&
m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 localPosition, out Quaternion localRotation, local: true))
{
if (m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 position, out Quaternion rotation) &&
m_HandMesh.GetJointPositionAndRotation((JointType)i, out Vector3 localPosition, out Quaternion localRotation, local: true))
{
m_Position[i] = position;
m_Rotation[i] = rotation;
m_LocalPosition[i] = localPosition;
m_LocalRotation[i] = localRotation;
}
else
{
m_Position[i] = Vector3.zero;
m_Rotation[i] = Quaternion.identity;
m_LocalPosition[i] = Vector3.zero;
m_LocalRotation[i] = Quaternion.identity;
}
m_Position[i] = position;
m_Rotation[i] = rotation;
m_LocalPosition[i] = localPosition;
m_LocalRotation[i] = localRotation;
}
else
{
m_Position[i] = Vector3.zero;
m_Rotation[i] = Quaternion.identity;
m_LocalPosition[i] = Vector3.zero;
m_LocalRotation[i] = Quaternion.identity;
}
}
}

View File

@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
protected override void OnDisable()
{
base.OnDisable();
if (keepUpdate)
{
keepUpdate = false;
StopCoroutine(UpdatePose());
}
keepUpdate = false;
}
public override void SetType(HandPoseType poseType)
@@ -43,41 +39,33 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
yield return new WaitUntil(() => m_Initialized);
base.OnEnable();
if (!keepUpdate)
{
keepUpdate = true;
StartCoroutine(UpdatePose());
}
keepUpdate = true;
}
private IEnumerator UpdatePose()
private void Update()
{
if (!keepUpdate) { return; }
HandData handData = CachedHand.Get(isLeft);
m_IsTracked = handData.isTracked;
if (!m_IsTracked) { return; }
Vector3 position = Vector3.zero;
Quaternion rotation = Quaternion.identity;
while (keepUpdate)
for (int i = 0; i < poseCount; i++)
{
yield return new WaitForEndOfFrame();
HandData handData = CachedHand.Get(isLeft);
m_IsTracked = handData.isTracked;
if (!m_IsTracked) { continue; }
for (int i = 0; i < poseCount; i++)
if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation))
{
if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation))
{
m_Position[i] = transform.position + transform.rotation * position;
m_Rotation[i] = transform.rotation * rotation;
m_LocalPosition[i] = position;
m_LocalRotation[i] = rotation;
}
else
{
m_Position[i] = Vector3.zero;
m_Rotation[i] = Quaternion.identity;
m_LocalPosition[i] = Vector3.zero;
m_LocalRotation[i] = Quaternion.identity;
}
m_Position[i] = transform.position + transform.rotation * position;
m_Rotation[i] = transform.rotation * rotation;
m_LocalPosition[i] = position;
m_LocalRotation[i] = rotation;
}
else
{
m_Position[i] = Vector3.zero;
m_Rotation[i] = Quaternion.identity;
m_LocalPosition[i] = Vector3.zero;
m_LocalRotation[i] = Quaternion.identity;
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
@@ -9,13 +10,15 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
[SerializeField]
private float forceMultiplier = 1.0f;
private readonly int MIN_POSE_SAMPLES = 2;
private readonly int MAX_POSE_SAMPLES = 10;
private const int MIN_POSE_SAMPLES = 2;
private const int MAX_POSE_SAMPLES = 10;
private readonly float MIN_VELOCITY = 0.5f;
private Rigidbody interactableRigidbody;
private List<Pose> movementPoses = new List<Pose>();
private List<float> timestamps = new List<float>();
private Pose[] movementPoses = new Pose[MAX_POSE_SAMPLES];
private float[] timestamps = new float[MAX_POSE_SAMPLES];
private int currentPoseIndex = 0;
private int poseCount = 0;
private bool isBegin = false;
private bool isEnd = false;
private object lockVel = new object();
@@ -36,7 +39,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
if (isEnd)
{
#if UNITY_6000_0_OR_NEWER
interactableRigidbody.linearVelocity = Vector3.zero;
#else
interactableRigidbody.velocity = Vector3.zero;
#endif
interactableRigidbody.angularVelocity = Vector3.zero;
Vector3 velocity = CalculateVelocity();
@@ -46,8 +53,10 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
interactableRigidbody = null;
movementPoses.Clear();
timestamps.Clear();
Array.Clear(movementPoses, 0, MAX_POSE_SAMPLES);
Array.Clear(timestamps, 0, MAX_POSE_SAMPLES);
currentPoseIndex = 0;
poseCount = 0;
isEnd = false;
}
}
@@ -55,28 +64,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private void RecordMovement()
{
float time = Time.time;
if (movementPoses.Count == 0 ||
timestamps[movementPoses.Count - 1] != time)
{
movementPoses.Add(new Pose(interactableRigidbody.position, interactableRigidbody.rotation));
timestamps.Add(time);
}
if (movementPoses.Count > MAX_POSE_SAMPLES)
int lastIndex = (currentPoseIndex + poseCount - 1) % MAX_POSE_SAMPLES;
if (poseCount == 0 || timestamps[lastIndex] != time)
{
movementPoses.RemoveAt(0);
timestamps.RemoveAt(0);
movementPoses[currentPoseIndex] = new Pose(interactableRigidbody.position, interactableRigidbody.rotation);
timestamps[currentPoseIndex] = time;
if (poseCount < MAX_POSE_SAMPLES)
{
poseCount++;
}
currentPoseIndex = (currentPoseIndex + 1) % MAX_POSE_SAMPLES;
}
}
private Vector3 CalculateVelocity()
{
if (movementPoses.Count >= MIN_POSE_SAMPLES)
if (poseCount >= MIN_POSE_SAMPLES)
{
List<Vector3> velocities = new List<Vector3>();
for (int i = 0; i < movementPoses.Count - 1; i++)
for (int i = 0; i < poseCount - 1; i++)
{
for (int j = i + 1; j < movementPoses.Count; j++)
for (int j = i + 1; j < poseCount; j++)
{
velocities.Add(GetVelocity(i, j));
}
@@ -89,9 +99,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Vector3 GetVelocity(int idx1, int idx2)
{
if (idx1 < 0 || idx1 >= movementPoses.Count
|| idx2 < 0 || idx2 >= movementPoses.Count
|| movementPoses.Count < MIN_POSE_SAMPLES)
if (idx1 < 0 || idx1 >= poseCount
|| idx2 < 0 || idx2 >= poseCount
|| poseCount < MIN_POSE_SAMPLES)
{
return Vector3.zero;
}