VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction/Runtime/UnityXR/Scripts/FromUnityXRHandDataSource.cs
IonutMocanu 48cccc22ad Main2
2025-09-08 11:13:29 +03:00

374 lines
15 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
#if USE_XR_HANDS
using UnityEngine.XR.Hands;
#endif
using UnityEngine.XR.Management;
namespace Oculus.Interaction.Input.UnityXR
{
/// <summary>
/// <para>Provides hand tracking data to Interaction SDK OpenXR via UnityXR Hands.</para>
/// </summary>
public class FromUnityXRHandDataSource : FromOpenXRHandDataSource
{
#if USE_XR_HANDS
[Tooltip("The XRHandSubsystem.UpdateType that will be used to drive this " +
"data source. The Dynamic update type is recommended, see Unity's " +
"documentation for further details.")]
[SerializeField]
private XRHandSubsystem.UpdateType _updateType = XRHandSubsystem.UpdateType.Dynamic;
#endif
[Header("Shared Configuration")]
[SerializeField]
private Handedness _handedness;
[SerializeField, Interface(typeof(ITrackingToWorldTransformer))]
private UnityEngine.Object _trackingToWorldTransformer;
private ITrackingToWorldTransformer TrackingToWorldTransformer;
private static string _metaAimHandActionMap = @"{
""maps"": [
{
""name"": ""MetaAimHand"",
""actions"": [
{
""name"": ""aimFlags"",
""expectedControlLayout"": ""Integer"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/aimFlags""
}
]
},
{
""name"": ""pinchStrengthIndex"",
""expectedControlLayout"": ""Axis"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/pinchStrengthIndex""
}
]
},
{
""name"": ""pinchStrengthMiddle"",
""expectedControlLayout"": ""Axis"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/pinchStrengthMiddle""
}
]
},
{
""name"": ""pinchStrengthRing"",
""expectedControlLayout"": ""Axis"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/pinchStrengthRing""
}
]
},
{
""name"": ""pinchStrengthLittle"",
""expectedControlLayout"": ""Axis"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/pinchStrengthLittle""
}
]
},
{
""name"": ""devicePosition"",
""expectedControlLayout"": ""Vector3"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/devicePosition""
}
]
},
{
""name"": ""deviceRotation"",
""expectedControlLayout"": ""Quaternion"",
""bindings"": [
{
""path"":""<MetaAimHand>{LeftHand}/deviceRotation""
}
]
}
]
}
]}";
[SerializeField]
private InputActionMap _metaAimHandBindingsLeft =
InputActionMap.FromJson(_metaAimHandActionMap).FirstOrDefault();
[SerializeField]
private InputActionMap _metaAimHandBindingsRight = InputActionMap
.FromJson(_metaAimHandActionMap.Replace("{LeftHand}", "{RightHand}")).FirstOrDefault();
private InputActionMap MetaAimHandBindings =>
(_handedness == Handedness.Left) ? _metaAimHandBindingsLeft : _metaAimHandBindingsRight;
private HandDataSourceConfig _config;
private InputAction _metaAimFlags;
private InputAction _pinchStrengthIndex;
private InputAction _pinchStrengthMiddle;
private InputAction _pinchStrengthRing;
private InputAction _pinchStrengthLittle;
private InputAction _devicePosition;
private InputAction _deviceRotation;
#if ISDK_OPENXR_HAND
#else
private readonly OpenXRHandDataAsset _dataAsset = new();
protected override OpenXRHandDataAsset OpenXRData => _dataAsset;
#endif
protected override void Awake()
{
base.Awake();
TrackingToWorldTransformer = _trackingToWorldTransformer as ITrackingToWorldTransformer;
UpdateConfig();
}
protected override void Start()
{
base.Start();
this.BeginStart(ref _started, () => base.Start());
this.AssertField(TrackingToWorldTransformer, nameof(TrackingToWorldTransformer));
#if USE_XR_HANDS
XRHandSubsystem m_Subsystem =
XRGeneralSettings.Instance?
.Manager?
.activeLoader?
.GetLoadedSubsystem<XRHandSubsystem>();
if (m_Subsystem != null)
{
m_Subsystem.updatedHands += OnHandUpdate;
m_Subsystem.trackingLost += OnTrackingLost;
}
#endif
UpdateConfig();
var handBindings = MetaAimHandBindings;
_metaAimFlags = handBindings["aimFlags"];
_pinchStrengthIndex = handBindings["pinchStrengthIndex"];
_pinchStrengthMiddle = handBindings["pinchStrengthMiddle"];
_pinchStrengthRing = handBindings["pinchStrengthRing"];
_pinchStrengthLittle = handBindings["pinchStrengthLittle"];
_devicePosition = handBindings["devicePosition"];
_deviceRotation = handBindings["deviceRotation"];
this.EndStart(ref _started);
}
protected override void OnEnable()
{
base.OnEnable();
MetaAimHandBindings.Enable();
}
protected override void OnDisable()
{
base.OnDisable();
MetaAimHandBindings.Disable();
}
private HandDataSourceConfig Config
{
get
{
if (_config != null)
{
return _config;
}
_config = new HandDataSourceConfig() { Handedness = _handedness };
return _config;
}
}
private void UpdateConfig()
{
Config.TrackingToWorldTransformer = TrackingToWorldTransformer;
Config.HandSkeleton = (_handedness == Handedness.Left)
? HandSkeleton.DefaultLeftSkeleton
: HandSkeleton.DefaultRightSkeleton;
_dataAsset.Config = Config;
}
#if USE_XR_HANDS
private void OnTrackingLost(XRHand hand)
{
if ((hand.handedness == UnityEngine.XR.Hands.Handedness.Left && _handedness != Handedness.Left)
|| (hand.handedness == UnityEngine.XR.Hands.Handedness.Right && _handedness != Handedness.Right))
{
return;
}
_dataAsset.IsConnected = _dataAsset.IsTracked = _dataAsset.IsDataValid = false;
MarkInputDataRequiresUpdate();
}
private void OnHandUpdate(XRHandSubsystem subsystem,
XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags,
XRHandSubsystem.UpdateType updateType)
{
if (updateType != _updateType)
{
return;
}
XRHand hand;
switch (_handedness)
{
case Handedness.Left
when (subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints)
|| subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose)):
hand = subsystem.leftHand;
break;
case Handedness.Right
when (subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.RightHandJoints)
|| subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose))
:
hand = subsystem.rightHand;
break;
default:
return;
}
_dataAsset.IsDataValid = subsystem.running && hand.isTracked;
_dataAsset.IsConnected = subsystem.running;
_dataAsset.IsTracked = hand.isTracked;
// XR_EXT_hand_tracking
_dataAsset.Root = hand.rootPose;
_dataAsset.RootPoseOrigin = PoseOrigin.RawTrackedPose;
#if ISDK_OPENXR_HAND
_dataAsset.IsHighConfidence = true;
for (var i = 0; i < Constants.NUM_FINGERS; i++)
{
_dataAsset.IsFingerHighConfidence[i] = true;
}
#endif
for (var i = XRHandJointID.BeginMarker.ToIndex();
i < XRHandJointID.EndMarker.ToIndex();
i++)
{
var jointID = XRHandJointIDUtility.FromIndex(i);
var trackingData = hand.GetJoint(jointID);
#if ISDK_OPENXR_HAND
int jointIndex = jointID switch
{
XRHandJointID.Palm => (int)HandJointId.HandPalm,
XRHandJointID.Wrist => (int)HandJointId.HandWristRoot,
_ => i
};
if (!trackingData.trackingState.HasFlag(XRHandJointTrackingState.Pose))
{
_dataAsset.IsHighConfidence = false;
if (FingersMetadata.JOINT_TO_FINGER_INDEX[jointIndex] > 0)
{
_dataAsset.IsFingerHighConfidence[FingersMetadata.JOINT_TO_FINGER_INDEX[jointIndex]] = false;
}
}
if (trackingData.TryGetPose(out var pose))
{
_dataAsset.JointPoses[jointIndex] = PoseUtils.Delta(_dataAsset.Root, pose);
}
if (trackingData.TryGetRadius(out var radius))
{
_dataAsset.JointRadii[jointIndex] = radius;
}
#else
_dataAsset.JointStates[i] = (OpenXRHandDataAsset.JointTrackingState)trackingData.trackingState;
if (trackingData.TryGetPose(out var pose))
{
_dataAsset.JointPoses[i] = pose;
}
if (trackingData.TryGetRadius(out var radius))
{
_dataAsset.JointRadiuses[i] = radius;
}
if (trackingData.TryGetAngularVelocity(out var angularVelocity))
{
_dataAsset.JointAngularVelocities[i] = angularVelocity;
}
if (trackingData.TryGetLinearVelocity(out var linearVelocity))
{
_dataAsset.JointLinearVelocities[i] = linearVelocity;
}
#endif
}
// XR_FB_hand_tracking_aim
#if ISDK_OPENXR_HAND
MetaAimFlags aimFlags = (MetaAimFlags)_metaAimFlags.ReadValue<int>();
_shouldMockHandTrackingAim = _dataAsset.IsDataValidAndConnected && aimFlags == MetaAimFlags.None;
_dataAsset.IsDominantHand = aimFlags.HasFlag(MetaAimFlags.DominantHand);
_dataAsset.IsFingerPinching[(int)HandFinger.Index] = aimFlags.HasFlag(MetaAimFlags.IndexPinching);
_dataAsset.IsFingerPinching[(int)HandFinger.Middle] = aimFlags.HasFlag(MetaAimFlags.MiddlePinching);
_dataAsset.IsFingerPinching[(int)HandFinger.Ring] = aimFlags.HasFlag(MetaAimFlags.RingPinching);
_dataAsset.IsFingerPinching[(int)HandFinger.Pinky] = aimFlags.HasFlag(MetaAimFlags.LittlePinching);
#else
_dataAsset.AimFlags = (OpenXRHandDataAsset.AimFlagsFB)_metaAimFlags.ReadValue<int>();
#endif
_dataAsset.FingerPinchStrength[(int)HandFinger.Index] = _pinchStrengthIndex.ReadValue<float>();
_dataAsset.FingerPinchStrength[(int)HandFinger.Middle] = _pinchStrengthMiddle.ReadValue<float>();
_dataAsset.FingerPinchStrength[(int)HandFinger.Ring] = _pinchStrengthRing.ReadValue<float>();
_dataAsset.FingerPinchStrength[(int)HandFinger.Pinky] = _pinchStrengthLittle.ReadValue<float>();
_dataAsset.PointerPose.position = _devicePosition.ReadValue<Vector3>();
_dataAsset.PointerPose.rotation = _deviceRotation.ReadValue<Quaternion>();
_dataAsset.PointerPoseOrigin = PoseOrigin.RawTrackedPose;
// Notify update
if (subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints) ||
subsystem.updateSuccessFlags.HasFlag(XRHandSubsystem.UpdateSuccessFlags.RightHandJoints))
{
MarkInputDataRequiresUpdate();
}
}
#endif
#region Inject
public void InjectTrackingToWorldTransformer(ITrackingToWorldTransformer trackingToWorldTransformer)
{
_trackingToWorldTransformer = trackingToWorldTransformer as UnityEngine.Object;
TrackingToWorldTransformer = trackingToWorldTransformer;
UpdateConfig();
}
#endregion
}
}