VR4Medical/ICI/Library/PackageCache/com.unity.xr.hands@b137b9cef9d8/Tests/Runtime/Tests.cs
2025-07-29 13:45:50 +03:00

724 lines
32 KiB
C#

using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SubsystemsImplementation.Extensions;
using UnityEngine.TestTools;
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
class Tests
{
[Test]
public void TestFingerIDsToJointIDs()
{
Assert.AreEqual((int)XRHandFingerID.Thumb.GetFrontJointID() + 3, (int)XRHandFingerID.Thumb.GetBackJointID());
Assert.AreEqual((int)XRHandFingerID.Index.GetFrontJointID() + 4, (int)XRHandFingerID.Index.GetBackJointID());
Assert.AreEqual((int)XRHandFingerID.Middle.GetFrontJointID() + 4, (int)XRHandFingerID.Middle.GetBackJointID());
Assert.AreEqual((int)XRHandFingerID.Ring.GetFrontJointID() + 4, (int)XRHandFingerID.Ring.GetBackJointID());
Assert.AreEqual((int)XRHandFingerID.Little.GetFrontJointID() + 4, (int)XRHandFingerID.Little.GetBackJointID());
Assert.IsTrue(XRHandFingerID.Thumb.GetBackJointID() < XRHandFingerID.Index.GetFrontJointID());
Assert.IsTrue(XRHandFingerID.Index.GetBackJointID() < XRHandFingerID.Middle.GetFrontJointID());
Assert.IsTrue(XRHandFingerID.Middle.GetBackJointID() < XRHandFingerID.Ring.GetFrontJointID());
Assert.IsTrue(XRHandFingerID.Ring.GetBackJointID() < XRHandFingerID.Little.GetFrontJointID());
}
[Test]
public void CanCreateTestSubsystem()
{
var subsystem = CreateTestSubsystem();
Assert.AreNotEqual(subsystem, null);
subsystem.Destroy();
}
[Test]
public void SubsystemAsksForHandLayoutDuringCreate()
{
var subsystem = CreateTestSubsystem();
var testProvider = subsystem.GetProvider() as TestHandProvider;
Assert.IsNotNull(testProvider);
Assert.AreEqual(1, testProvider.numGetHandLayoutCalls);
subsystem.Destroy();
}
[Test]
public void SubsystemWontAskProviderForHandDataWithoutStarting()
{
var subsystem = CreateTestSubsystem();
for (var call = 0; call < 10; ++call)
{
var flags = subsystem.TryUpdateHands(
((call & 1) != 0)
? XRHandSubsystem.UpdateType.Dynamic
: XRHandSubsystem.UpdateType.BeforeRender);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.None, flags);
}
var testProvider = subsystem.GetProvider() as TestHandProvider;
Assert.IsNotNull(testProvider);
Assert.AreEqual(0, testProvider.numTryUpdateHandsCalls);
subsystem.Destroy();
}
[Test]
public void SubsystemAsksForHandsDataIfRunning()
{
const int numUpdates = 10;
var subsystem = CreateTestSubsystem();
subsystem.Start();
for (var call = 0; call < numUpdates; ++call)
{
var flags = subsystem.TryUpdateHands(
((call & 1) != 0)
? XRHandSubsystem.UpdateType.Dynamic
: XRHandSubsystem.UpdateType.BeforeRender);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.All, flags);
}
var testProvider = subsystem.GetProvider() as TestHandProvider;
Assert.IsNotNull(testProvider);
Assert.AreEqual(numUpdates, testProvider.numTryUpdateHandsCalls);
subsystem.Destroy();
}
[Test]
public void HandsMarkedWithCorrectHandedness()
{
var subsystem = CreateTestSubsystem();
Assert.AreEqual(Handedness.Left, subsystem.leftHand.handedness);
Assert.AreEqual(Handedness.Right, subsystem.rightHand.handedness);
subsystem.Destroy();
}
[Test]
public void StopIsCalledImplcitlyOnDestroyIfRunning()
{
var subsystem = CreateTestSubsystem();
subsystem.Start();
subsystem.Destroy();
var testProvider = subsystem.GetProvider() as TestHandProvider;
Assert.IsNotNull(testProvider);
Assert.AreEqual(1, testProvider.numStartCalls);
Assert.AreEqual(1, testProvider.numStopCalls);
Assert.AreEqual(1, testProvider.numDestroyCalls);
}
[Test]
public void ProviderGivesValidHandDataWhenRunning()
{
var subsystem = CreateTestSubsystem();
subsystem.Start();
var updateFlags = subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.All, updateFlags);
AssertAreApproximatelyEqual(TestHandData.leftRoot, subsystem.leftHand.rootPose);
AssertAreApproximatelyEqual(TestHandData.rightRoot, subsystem.rightHand.rootPose);
int numValidLeftJoints = 0, numValidRightJoints = 0;
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
var id = XRHandJointIDUtility.FromIndex(jointIndex);
var leftJoint = subsystem.leftHand.GetJoint(id);
if (leftJoint.TryGetPose(out var leftPose))
{
++numValidLeftJoints;
AssertAreApproximatelyEqual(TestHandData.leftHand[jointIndex], leftPose);
}
else
{
Assert.IsFalse(subsystem.jointsInLayout[jointIndex]);
}
var rightJoint = subsystem.rightHand.GetJoint(id);
if (rightJoint.TryGetPose(out var rightPose))
{
++numValidRightJoints;
AssertAreApproximatelyEqual(TestHandData.rightHand[jointIndex], rightPose);
}
else
{
Assert.IsFalse(subsystem.jointsInLayout[jointIndex]);
}
}
Assert.AreEqual(26, numValidLeftJoints);
Assert.AreEqual(26, numValidRightJoints);
subsystem.Destroy();
}
[Test]
public void MockProviderOnlyGivesHandPosesAndSensibleDefaults()
{
var subsystem = CreateTestSubsystem();
subsystem.Start();
var updateFlags = subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.All, updateFlags);
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
var id = XRHandJointIDUtility.FromIndex(jointIndex);
var leftJoint = subsystem.leftHand.GetJoint(id);
Assert.AreEqual(XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose, leftJoint.trackingState);
Assert.IsFalse(leftJoint.TryGetRadius(out var leftRadius));
Assert.IsFalse(leftJoint.TryGetLinearVelocity(out var leftLinearVelocity));
Assert.IsFalse(leftJoint.TryGetAngularVelocity(out var leftAngularVelocity));
Assert.AreEqual(0f, leftRadius);
Assert.AreEqual(Vector3.zero, leftLinearVelocity);
Assert.AreEqual(Vector3.zero, leftAngularVelocity);
var rightJoint = subsystem.rightHand.GetJoint(id);
Assert.AreEqual(XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose, rightJoint.trackingState);
Assert.IsFalse(rightJoint.TryGetRadius(out var rightRadius));
Assert.IsFalse(rightJoint.TryGetLinearVelocity(out var rightLinearVelocity));
Assert.IsFalse(rightJoint.TryGetAngularVelocity(out var rightAngularVelocity));
Assert.AreEqual(0f, rightRadius);
Assert.AreEqual(Vector3.zero, rightLinearVelocity);
Assert.AreEqual(Vector3.zero, rightAngularVelocity);
}
subsystem.Destroy();
}
[Test]
public void XRHandJointToStringNeverNull()
{
var subsystem = CreateTestSubsystem();
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
var id = XRHandJointIDUtility.FromIndex(jointIndex);
var leftJoint = subsystem.leftHand.GetJoint(id);
var rightJoint = subsystem.rightHand.GetJoint(id);
Assert.AreNotEqual(null, leftJoint.ToString());
Assert.AreNotEqual(null, rightJoint.ToString());
}
subsystem.Destroy();
}
[Test]
public void ToIndexJustSubtractsOne()
{
Assert.AreEqual(XRHandJointID.Invalid.ToIndex(), (int)XRHandJointID.Invalid - 1);
Assert.AreEqual(XRHandJointID.BeginMarker.ToIndex(), (int)XRHandJointID.BeginMarker - 1);
Assert.AreEqual(XRHandJointID.Wrist.ToIndex(), (int)XRHandJointID.Wrist - 1);
Assert.AreEqual(XRHandJointID.Palm.ToIndex(), (int)XRHandJointID.Palm - 1);
Assert.AreEqual(XRHandJointID.ThumbMetacarpal.ToIndex(), (int)XRHandJointID.ThumbMetacarpal - 1);
Assert.AreEqual(XRHandJointID.ThumbProximal.ToIndex(), (int)XRHandJointID.ThumbProximal - 1);
Assert.AreEqual(XRHandJointID.ThumbDistal.ToIndex(), (int)XRHandJointID.ThumbDistal - 1);
Assert.AreEqual(XRHandJointID.ThumbTip.ToIndex(), (int)XRHandJointID.ThumbTip - 1);
Assert.AreEqual(XRHandJointID.IndexMetacarpal.ToIndex(), (int)XRHandJointID.IndexMetacarpal - 1);
Assert.AreEqual(XRHandJointID.IndexProximal.ToIndex(), (int)XRHandJointID.IndexProximal - 1);
Assert.AreEqual(XRHandJointID.IndexIntermediate.ToIndex(), (int)XRHandJointID.IndexIntermediate - 1);
Assert.AreEqual(XRHandJointID.IndexDistal.ToIndex(), (int)XRHandJointID.IndexDistal - 1);
Assert.AreEqual(XRHandJointID.IndexTip.ToIndex(), (int)XRHandJointID.IndexTip - 1);
Assert.AreEqual(XRHandJointID.MiddleMetacarpal.ToIndex(), (int)XRHandJointID.MiddleMetacarpal - 1);
Assert.AreEqual(XRHandJointID.MiddleProximal.ToIndex(), (int)XRHandJointID.MiddleProximal - 1);
Assert.AreEqual(XRHandJointID.MiddleIntermediate.ToIndex(), (int)XRHandJointID.MiddleIntermediate - 1);
Assert.AreEqual(XRHandJointID.MiddleDistal.ToIndex(), (int)XRHandJointID.MiddleDistal - 1);
Assert.AreEqual(XRHandJointID.MiddleTip.ToIndex(), (int)XRHandJointID.MiddleTip - 1);
Assert.AreEqual(XRHandJointID.RingMetacarpal.ToIndex(), (int)XRHandJointID.RingMetacarpal - 1);
Assert.AreEqual(XRHandJointID.RingProximal.ToIndex(), (int)XRHandJointID.RingProximal - 1);
Assert.AreEqual(XRHandJointID.RingIntermediate.ToIndex(), (int)XRHandJointID.RingIntermediate - 1);
Assert.AreEqual(XRHandJointID.RingDistal.ToIndex(), (int)XRHandJointID.RingDistal - 1);
Assert.AreEqual(XRHandJointID.RingTip.ToIndex(), (int)XRHandJointID.RingTip - 1);
Assert.AreEqual(XRHandJointID.LittleMetacarpal.ToIndex(), (int)XRHandJointID.LittleMetacarpal - 1);
Assert.AreEqual(XRHandJointID.LittleProximal.ToIndex(), (int)XRHandJointID.LittleProximal - 1);
Assert.AreEqual(XRHandJointID.LittleIntermediate.ToIndex(), (int)XRHandJointID.LittleIntermediate - 1);
Assert.AreEqual(XRHandJointID.LittleDistal.ToIndex(), (int)XRHandJointID.LittleDistal - 1);
Assert.AreEqual(XRHandJointID.LittleTip.ToIndex(), (int)XRHandJointID.LittleTip - 1);
Assert.AreEqual(XRHandJointID.EndMarker.ToIndex(), (int)XRHandJointID.EndMarker - 1);
}
[Test]
public void FromIndexJustAddsOne()
{
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.Invalid - 1), XRHandJointID.Invalid);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.BeginMarker - 1), XRHandJointID.BeginMarker);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.Wrist - 1), XRHandJointID.Wrist);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.Palm - 1), XRHandJointID.Palm);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.ThumbMetacarpal - 1), XRHandJointID.ThumbMetacarpal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.ThumbProximal - 1), XRHandJointID.ThumbProximal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.ThumbDistal - 1), XRHandJointID.ThumbDistal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.ThumbTip - 1), XRHandJointID.ThumbTip);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.IndexMetacarpal - 1), XRHandJointID.IndexMetacarpal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.IndexProximal - 1), XRHandJointID.IndexProximal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.IndexIntermediate - 1), XRHandJointID.IndexIntermediate);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.IndexDistal - 1), XRHandJointID.IndexDistal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.IndexTip - 1), XRHandJointID.IndexTip);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.MiddleMetacarpal - 1), XRHandJointID.MiddleMetacarpal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.MiddleProximal - 1), XRHandJointID.MiddleProximal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.MiddleIntermediate - 1), XRHandJointID.MiddleIntermediate);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.MiddleDistal - 1), XRHandJointID.MiddleDistal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.MiddleTip - 1), XRHandJointID.MiddleTip);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.RingMetacarpal - 1), XRHandJointID.RingMetacarpal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.RingProximal - 1), XRHandJointID.RingProximal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.RingIntermediate - 1), XRHandJointID.RingIntermediate);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.RingDistal - 1), XRHandJointID.RingDistal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.RingTip - 1), XRHandJointID.RingTip);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.LittleMetacarpal - 1), XRHandJointID.LittleMetacarpal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.LittleProximal - 1), XRHandJointID.LittleProximal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.LittleIntermediate - 1), XRHandJointID.LittleIntermediate);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.LittleDistal - 1), XRHandJointID.LittleDistal);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.LittleTip - 1), XRHandJointID.LittleTip);
Assert.AreEqual(XRHandJointIDUtility.FromIndex((int)XRHandJointID.EndMarker - 1), XRHandJointID.EndMarker);
}
[Test]
public void SubsystemPassesUpdateTypeDirectlyToProvider()
{
var subsystem = CreateTestSubsystem();
var testProvider = subsystem.GetProvider() as TestHandProvider;
subsystem.Start();
subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);
Assert.IsNotNull(testProvider);
Assert.AreEqual(XRHandSubsystem.UpdateType.Dynamic, testProvider.mostRecentUpdateType);
subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.BeforeRender);
Assert.AreEqual(XRHandSubsystem.UpdateType.BeforeRender, testProvider.mostRecentUpdateType);
subsystem.Destroy();
}
[Test]
public void HandsUpdatedCallbackWorks()
{
var flags = XRHandSubsystem.UpdateSuccessFlags.None;
void OnUpdatedHands(XRHandSubsystem xrHandSubsystem, XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags, XRHandSubsystem.UpdateType updateType) => flags = updateSuccessFlags;
var subsystem = CreateTestSubsystem();
subsystem.updatedHands += OnUpdatedHands;
subsystem.Start();
subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.All, flags);
subsystem.Destroy();
}
[Test]
public void DescriptorCinfoEqualsReturnsTrue()
{
var testCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = TestHandProvider.descriptorId,
providerType = typeof(TestHandProvider)
};
var testCinfo2 = new XRHandSubsystemDescriptor.Cinfo
{
id = TestHandProvider.descriptorId,
providerType = typeof(TestHandProvider)
};
Assert.IsTrue(testCinfo.Equals(testCinfo2));
Assert.AreEqual(testCinfo.GetHashCode(), testCinfo2.GetHashCode());
}
[Test]
public void DescriptorCinfoEqualsReturnsFalse()
{
var testCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = TestHandProvider.descriptorId,
providerType = typeof(TestHandProvider)
};
var testCinfo2 = new XRHandSubsystemDescriptor.Cinfo
{
id = "Dummy-Hands"
};
Assert.IsFalse(testCinfo.Equals(testCinfo2));
Assert.AreNotEqual(testCinfo.GetHashCode(), testCinfo2.GetHashCode());
}
[Test]
public void JointIDsMatch()
{
var subsystem = CreateTestSubsystem();
subsystem.Start();
var flags = subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);
Assert.AreEqual(XRHandSubsystem.UpdateSuccessFlags.All, flags);
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
var id = XRHandJointIDUtility.FromIndex(jointIndex);
var leftJoint = subsystem.leftHand.GetJoint(id);
var rightJoint = subsystem.rightHand.GetJoint(id);
Assert.AreEqual(id, leftJoint.id);
Assert.AreEqual(id, rightJoint.id);
}
subsystem.Destroy();
}
[Test]
public void TestJointsAreInSubsystemLayout()
{
var subsystem = CreateTestSubsystem();
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
Assert.AreEqual(TestHandData.jointsInLayout[jointIndex], subsystem.jointsInLayout[jointIndex]);
}
subsystem.Destroy();
}
[UnityTest]
public IEnumerator SubsystemUpdaterWorks()
{
var subsystem = CreateTestSubsystem();
var updater = new XRHandProviderUtility.SubsystemUpdater(subsystem);
try
{
bool updated = false;
void OnUpdatedHands(XRHandSubsystem xrHandSubsystem, XRHandSubsystem.UpdateSuccessFlags successFlags, XRHandSubsystem.UpdateType updateType) => updated = true;
subsystem.updatedHands += OnUpdatedHands;
subsystem.Start();
updater.Start();
yield return null;
Assert.IsTrue(updated);
}
finally
{
updater.Stop();
updater.Destroy();
subsystem.Destroy();
}
}
[UnityTest]
public IEnumerator HandTrackingEventCallbacks()
{
var subsystem = CreateTestSubsystem();
var updater = new XRHandProviderUtility.SubsystemUpdater(subsystem);
var provider = (TestHandProvider)subsystem.GetProvider();
var go = new GameObject("TestHandTrackingEvents");
try
{
subsystem.Start();
updater.Start();
yield return null;
var rightHandTrackingEvents = go.AddComponent<XRHandTrackingEvents>();
rightHandTrackingEvents.handedness = Handedness.Right;
rightHandTrackingEvents.updateType = XRHandTrackingEvents.UpdateTypes.Dynamic;
bool jointsUpdated = false, poseUpdated = false, trackingAcquired = false, trackingLost = false, trackingStateChanged = false;
var jointsUpdateCallbackCount = 0;
rightHandTrackingEvents.trackingAcquired.AddListener(() => trackingAcquired = true);
rightHandTrackingEvents.trackingLost.AddListener(() => trackingLost = true);
rightHandTrackingEvents.trackingChanged.AddListener(_ => trackingStateChanged = true);
rightHandTrackingEvents.jointsUpdated.AddListener(_ =>
{
jointsUpdateCallbackCount++;
jointsUpdated = true;
});
rightHandTrackingEvents.poseUpdated.AddListener(_ =>
{
poseUpdated = true;
});
rightHandTrackingEvents.SetSubsystem(subsystem);
yield return null;
// First acquire and first update
Assert.AreEqual(1, jointsUpdateCallbackCount);
Assert.IsTrue(rightHandTrackingEvents.handIsTracked);
Assert.IsTrue(trackingAcquired);
Assert.IsFalse(trackingLost);
Assert.IsTrue(trackingStateChanged);
Assert.IsTrue(jointsUpdated);
Assert.IsTrue(poseUpdated);
trackingStateChanged = false;
yield return null;
// Second update, no change to tracking state
Assert.AreEqual(2, jointsUpdateCallbackCount);
Assert.IsTrue(rightHandTrackingEvents.handIsTracked);
Assert.IsFalse(trackingStateChanged);
jointsUpdated = poseUpdated = trackingAcquired = trackingLost = trackingStateChanged = false;
provider.rightHandIsTracked = false;
yield return null;
// Tracking changed (lost) no joints updated
Assert.AreEqual(2, jointsUpdateCallbackCount);
Assert.IsFalse(rightHandTrackingEvents.handIsTracked);
Assert.IsTrue(trackingLost);
Assert.IsTrue(trackingStateChanged);
Assert.IsFalse(trackingAcquired);
Assert.IsFalse(jointsUpdated);
Assert.IsFalse(poseUpdated);
jointsUpdated = poseUpdated = trackingAcquired = trackingLost = trackingStateChanged = false;
provider.rightHandIsTracked = true;
yield return null;
// Tracking changed (acquired) and updated again
Assert.AreEqual(3, jointsUpdateCallbackCount);
Assert.IsTrue(rightHandTrackingEvents.handIsTracked);
Assert.IsTrue(trackingAcquired);
Assert.IsFalse(trackingLost);
Assert.IsTrue(trackingStateChanged);
Assert.IsTrue(jointsUpdated);
Assert.IsTrue(poseUpdated);
// Stopping tracking on the left hand does not affect the right hand
jointsUpdated = poseUpdated = trackingAcquired = trackingLost = trackingStateChanged = false;
provider.leftHandIsTracked = false;
yield return null;
Assert.AreEqual(4, jointsUpdateCallbackCount);
Assert.IsTrue(rightHandTrackingEvents.handIsTracked);
Assert.IsFalse(trackingAcquired);
Assert.IsFalse(trackingLost);
Assert.IsFalse(trackingStateChanged);
Assert.IsTrue(jointsUpdated);
Assert.IsTrue(poseUpdated);
}
finally
{
Object.DestroyImmediate(go);
updater.Stop();
updater.Destroy();
subsystem.Destroy();
}
}
[UnityTest]
public IEnumerator HandTrackingPoseStatusUpdates()
{
var subsystem = CreateTestSubsystem();
var updater = new XRHandProviderUtility.SubsystemUpdater(subsystem);
var provider = (TestHandProvider)subsystem.GetProvider();
int[] fingerTipIndices =
{
XRHandJointID.ThumbTip.ToIndex(),
XRHandJointID.IndexTip.ToIndex(),
XRHandJointID.MiddleTip.ToIndex(),
XRHandJointID.RingTip.ToIndex(),
XRHandJointID.LittleTip.ToIndex()
};
XRHandJointTrackingState[] expectedLeftHandJointsTrackingStates = new XRHandJointTrackingState[XRHandJointID.EndMarker.ToIndex()];
XRHandJointTrackingState[] expectedRightHandJointsTrackingStates = new XRHandJointTrackingState[XRHandJointID.EndMarker.ToIndex()];
System.Array.Fill(expectedLeftHandJointsTrackingStates, XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose);
System.Array.Fill(expectedRightHandJointsTrackingStates, XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose);
bool leftHandJointsUpdatedThisFrame = false;
XRHandJointTrackingState[] actualLeftHandJointsTrackingStates = new XRHandJointTrackingState[XRHandJointID.EndMarker.ToIndex()];
bool rightHandJointsUpdatedThisFrame = false;
XRHandJointTrackingState[] actualRightHandJointsTrackingStates = new XRHandJointTrackingState[XRHandJointID.EndMarker.ToIndex()];
void OnUpdatedHands(
XRHandSubsystem xrHandSubsystem,
XRHandSubsystem.UpdateSuccessFlags successFlags,
XRHandSubsystem.UpdateType updateType)
{
if (updateType != XRHandSubsystem.UpdateType.Dynamic)
return;
leftHandJointsUpdatedThisFrame = successFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose)
&& successFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints);
rightHandJointsUpdatedThisFrame = successFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose)
&& successFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.RightHandJoints);
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex();
jointIndex < XRHandJointID.EndMarker.ToIndex();
++jointIndex)
{
if (leftHandJointsUpdatedThisFrame)
{
actualLeftHandJointsTrackingStates[jointIndex] =
xrHandSubsystem.leftHand.GetJoint(XRHandJointIDUtility.FromIndex(jointIndex)).trackingState;
}
if (rightHandJointsUpdatedThisFrame)
{
actualRightHandJointsTrackingStates[jointIndex] =
xrHandSubsystem.rightHand.GetJoint(XRHandJointIDUtility.FromIndex(jointIndex)).trackingState;
}
}
}
subsystem.updatedHands += OnUpdatedHands;
try
{
subsystem.Start();
updater.Start();
yield return null;
Assert.IsTrue(leftHandJointsUpdatedThisFrame);
Assert.IsTrue(rightHandJointsUpdatedThisFrame);
Assert.IsTrue(expectedLeftHandJointsTrackingStates.SequenceEqual(actualLeftHandJointsTrackingStates));
Assert.IsTrue(expectedRightHandJointsTrackingStates.SequenceEqual(actualRightHandJointsTrackingStates));
// Mark some of the joints as having low-fidelity poses, as if they are occluded. Only mark the left hand.
foreach (var fingerTipIndex in fingerTipIndices)
{
expectedLeftHandJointsTrackingStates[fingerTipIndex] = XRHandJointTrackingState.Pose;
}
expectedLeftHandJointsTrackingStates.CopyTo(provider.leftHandJointsTrackingStates, 0);
yield return null;
Assert.IsTrue(leftHandJointsUpdatedThisFrame);
Assert.IsTrue(rightHandJointsUpdatedThisFrame);
Assert.IsTrue(expectedLeftHandJointsTrackingStates.SequenceEqual(actualLeftHandJointsTrackingStates));
Assert.IsTrue(expectedRightHandJointsTrackingStates.SequenceEqual(actualRightHandJointsTrackingStates));
// Now mark the finger tips of the right hand as occluded.
foreach (var fingerTipIndex in fingerTipIndices)
{
expectedRightHandJointsTrackingStates[fingerTipIndex] = XRHandJointTrackingState.Pose;
}
expectedRightHandJointsTrackingStates.CopyTo(provider.rightHandJointsTrackingStates, 0);
yield return null;
Assert.IsTrue(leftHandJointsUpdatedThisFrame);
Assert.IsTrue(rightHandJointsUpdatedThisFrame);
Assert.IsTrue(expectedLeftHandJointsTrackingStates.SequenceEqual(actualLeftHandJointsTrackingStates));
Assert.IsTrue(expectedRightHandJointsTrackingStates.SequenceEqual(actualRightHandJointsTrackingStates));
// Unocclude the left hand.
foreach (var fingerTipIndex in fingerTipIndices)
{
expectedLeftHandJointsTrackingStates[fingerTipIndex] = XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose;
}
expectedLeftHandJointsTrackingStates.CopyTo(provider.leftHandJointsTrackingStates, 0);
yield return null;
Assert.IsTrue(leftHandJointsUpdatedThisFrame);
Assert.IsTrue(rightHandJointsUpdatedThisFrame);
Assert.IsTrue(expectedLeftHandJointsTrackingStates.SequenceEqual(actualLeftHandJointsTrackingStates));
Assert.IsTrue(expectedRightHandJointsTrackingStates.SequenceEqual(actualRightHandJointsTrackingStates));
// ...and now the right hand.
foreach (var fingerTipIndex in fingerTipIndices)
{
expectedRightHandJointsTrackingStates[fingerTipIndex] = XRHandJointTrackingState.Pose | XRHandJointTrackingState.HighFidelityPose;
}
expectedRightHandJointsTrackingStates.CopyTo(provider.rightHandJointsTrackingStates, 0);
yield return null;
Assert.IsTrue(leftHandJointsUpdatedThisFrame);
Assert.IsTrue(rightHandJointsUpdatedThisFrame);
Assert.IsTrue(expectedLeftHandJointsTrackingStates.SequenceEqual(actualLeftHandJointsTrackingStates));
Assert.IsTrue(expectedRightHandJointsTrackingStates.SequenceEqual(actualRightHandJointsTrackingStates));
}
finally
{
updater.Stop();
updater.Destroy();
subsystem.Destroy();
}
}
static void EnsureTestSubsystemDescriptorRegistered()
{
var descriptors = new List<XRHandSubsystemDescriptor>();
SubsystemManager.GetSubsystemDescriptors(descriptors);
foreach (var descriptor in descriptors)
{
if (descriptor.id == TestHandProvider.descriptorId)
return;
}
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = TestHandProvider.descriptorId,
providerType = typeof(TestHandProvider)
};
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
}
static XRHandSubsystem CreateTestSubsystem()
{
EnsureTestSubsystemDescriptorRegistered();
var descriptors = new List<XRHandSubsystemDescriptor>();
SubsystemManager.GetSubsystemDescriptors(descriptors);
foreach (var descriptor in descriptors)
{
if (descriptor.id == TestHandProvider.descriptorId)
return descriptor.Create();
}
return null;
}
static void AssertAreApproximatelyEqual(float expected, float actual)
{
Assert.IsTrue(Mathf.Abs(actual - expected) <= k_EpsilonSqrt);
}
static void AssertAreApproximatelyEqual(Vector3 expected, Vector3 actual)
{
AssertAreApproximatelyEqual(expected.x, actual.x);
AssertAreApproximatelyEqual(expected.y, actual.y);
AssertAreApproximatelyEqual(expected.z, actual.z);
}
static void AssertAreApproximatelyEqual(Quaternion expected, Quaternion actual)
{
AssertAreApproximatelyEqual(expected.x, actual.x);
AssertAreApproximatelyEqual(expected.y, actual.y);
AssertAreApproximatelyEqual(expected.z, actual.z);
AssertAreApproximatelyEqual(expected.w, actual.w);
}
static void AssertAreApproximatelyEqual(Pose expected, Pose actual)
{
AssertAreApproximatelyEqual(expected.position, actual.position);
AssertAreApproximatelyEqual(expected.rotation, actual.rotation);
}
static readonly float k_EpsilonSqrt = Mathf.Sqrt(Mathf.Epsilon);
}