using System; using System.Runtime.InteropServices; using UnityEngine.XR.Hands.ProviderImplementation; namespace UnityEngine.XR.Hands { /// /// Represents a joint of an . /// /// /// The term "joint" should be taken loosely in this context. In addition to the /// anatomical finger joints, the list of joints includes the fingertips, a point on the palm /// and a point on the wrist. See for the full list of /// joints. /// /// Refer to [Hand data model](xref:xrhands-data-model) for a description of the joint locations /// and the data they contain. /// [StructLayout(LayoutKind.Sequential)] public struct XRHandJoint : IEquatable { /// /// The ID of this joint. /// /// The joint ID. public XRHandJointID id => (XRHandJointID)(m_IdAndHandedness & ~k_IsRightHandBit); /// /// Denotes which hand this joint is on. /// /// Right or left. public Handedness handedness => (m_IdAndHandedness & k_IsRightHandBit) != 0 ? Handedness.Right : Handedness.Left; /// /// Represents which tracking data is valid. /// /// A flag is set for each valid type of data. If the /// The flag is set /// when this joind ID isn't supported by the hand data provider. public XRHandJointTrackingState trackingState => m_TrackingState; /// /// Retrieves the joint's radius, if available. /// /// /// Assigned the tracked radius of this joint, if successful. /// Set to zero, if unsuccessful. /// /// /// Returns if successful and the radius was /// filled out with valid tracking data, returns /// otherwise. /// public bool TryGetRadius(out float radius) { if ((m_TrackingState & XRHandJointTrackingState.Radius) == XRHandJointTrackingState.None) { radius = 0.0f; return false; } radius = m_Radius; return true; } /// /// Retrieves the joint's pose, if available. /// /// /// Assigned the tracked pose of this joint, if successful. /// Set to , if unsuccessful. /// /// /// Returns if successful and the joint pose was /// filled out with valid tracking data, returns /// otherwise. /// /// /// Joint poses are relative to the real-world point chosen by the user's device. /// /// To transform to world space so that the joint appears in the correct location /// relative to the user, transform the pose based on the /// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin). /// /// /// /// The following example illustrates how to transform a pose into world space using the /// transform from the XROrigin object in a scene. /// /// /// public Pose ToWorldPose(XRHandJoint joint, Transform origin) /// { /// Pose xrOriginPose = new Pose(origin.position, origin.rotation); /// if (joint.TryGetPose(out Pose jointPose)) /// { /// return jointPose.GetTransformedBy(xrOriginPose); /// } /// else /// { /// return Pose.identity; /// } /// } /// /// public bool TryGetPose(out Pose pose) { if ((m_TrackingState & XRHandJointTrackingState.Pose) == XRHandJointTrackingState.None) { pose = Pose.identity; return false; } pose = m_Pose; return true; } /// /// Retrieves the joint's linear velocity vector, if available. /// /// /// Assigned the tracked linear velocity of this joint, if successful. /// Set to , if unsuccessful. /// /// /// Returns if successful and the velocity was /// filled out with valid tracking data, returns /// otherwise. /// /// /// To transform to world space so that the vector has the correct direction /// relative to the user, rotate this by the rotation of the /// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin). /// public bool TryGetLinearVelocity(out Vector3 linearVelocity) { if ((m_TrackingState & XRHandJointTrackingState.LinearVelocity) == XRHandJointTrackingState.None) { linearVelocity = Vector3.zero; return false; } linearVelocity = m_LinearVelocity; return true; } /// /// Retrieves the joint's angular velocity vector, if available /// /// /// Assigned the tracked angular velocity of this joint, if successful. /// Set to , if unsuccessful. /// /// /// Returns if successful and the angular /// velocity filled out with valid tracking data, returns /// otherwise. /// /// /// To transform to world space so that the vector has the correct direction /// relative to the user, rotate this by the rotation of the /// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin). /// public bool TryGetAngularVelocity(out Vector3 angularVelocity) { if ((m_TrackingState & XRHandJointTrackingState.AngularVelocity) == XRHandJointTrackingState.None) { angularVelocity = Vector3.zero; return false; } angularVelocity = m_AngularVelocity; return true; } /// /// Returns a string representation of the XRHandJoint. /// /// /// String representation of the value. /// public override string ToString() { return string.Format( "[{0} {1}] Pose: {2} | Radius: {3} | Linear Velocity: {4} | Angular Velocity: {5} | Tracking State: {6}", handedness, id, m_Pose.ToString("F4"), m_Radius.ToString("F4"), m_LinearVelocity.ToString("F4"), m_AngularVelocity.ToString("F4"), m_TrackingState); } /// /// Tests for equality. /// /// The to compare against. /// /// Returns if the underlying native pointers are /// the same. Returns otherwise. /// public bool Equals(XRHandJoint other) { return m_IdAndHandedness == other.m_IdAndHandedness && m_Pose == other.m_Pose && m_Radius == other.m_Radius && m_LinearVelocity == other.m_LinearVelocity && m_AngularVelocity == other.m_AngularVelocity && m_TrackingState == other.m_TrackingState; } /// /// Tests for equality. /// /// An to compare against. /// /// Returns if is an /// and it compares equal to this one using /// . /// public override bool Equals(object obj) => obj is XRHandJoint other && Equals(other); /// /// Computes a hash code from all fields of XRHandJoint. /// /// Returns a hash code of this object. public override int GetHashCode() { unchecked { int hash = m_IdAndHandedness.GetHashCode(); hash = hash * 486187739 + m_Pose.GetHashCode(); hash = hash * 486187739 + m_Radius.GetHashCode(); hash = hash * 486187739 + m_LinearVelocity.GetHashCode(); hash = hash * 486187739 + m_AngularVelocity.GetHashCode(); hash = hash * 486187739 + m_TrackingState.GetHashCode(); return hash; } } /// /// Tests for equality. Same as . /// /// The left-hand side of the comparison. /// The right-hand side of the comparison. /// Returns the same value as . public static bool operator ==(XRHandJoint lhs, XRHandJoint rhs) => lhs.Equals(rhs); /// /// Tests for inequality. Same as ! /// /// The left-hand side of the comparison. /// The right-hand side of the comparison. /// Returns the negation of . public static bool operator !=(XRHandJoint lhs, XRHandJoint rhs) => !lhs.Equals(rhs); internal int m_IdAndHandedness; internal Pose m_Pose; internal float m_Radius; internal Vector3 m_LinearVelocity; internal Vector3 m_AngularVelocity; internal XRHandJointTrackingState m_TrackingState; internal const int k_IsRightHandBit = 1 << 31; } }