// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System.Collections.Generic; using System.Linq; using UltimateXR.Avatar; using UltimateXR.Core; using UltimateXR.Extensions.Unity; using UltimateXR.Manipulation.HandPoses; using UnityEngine; namespace UltimateXR.Manipulation { public partial class UxrGrabManager { #region Public Methods /// /// Checks whether an can grab something using the given hand. /// /// Avatar to check /// Whether to check the left or right hand /// Whether something can be grabbed public bool CanGrabSomething(UxrAvatar avatar, UxrHandSide handSide) { foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide) { return CanGrabSomething(grabber); } } return false; } /// /// Checks whether a can grab something using the given grabber. /// /// Grabber to check /// Whether something can be grabbed public bool CanGrabSomething(UxrGrabber grabber) { foreach (UxrGrabbableObject grabbableObject in UxrGrabbableObject.EnabledComponents) { if (grabbableObject.IsGrabbable) { for (int point = 0; point < grabbableObject.GrabPointCount; ++point) { if (grabbableObject.CanBeGrabbedByGrabber(grabber, point)) { return true; } } } } return false; } /// /// Gets the closest grabbable object that can be grabbed by an using the given hand. /// /// Avatar to check /// Whether to check the left hand or right hand /// Returns the closest grabbable object or null if none was found /// Whether a grabbable object was found public bool GetClosestGrabbableObject(UxrAvatar avatar, UxrHandSide handSide, out UxrGrabbableObject grabbableObject) { grabbableObject = null; foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide) { return GetClosestGrabbableObject(avatar, handSide, out grabbableObject, out int _); } } return false; } /// /// Gets the closest grabbable object that can be grabbed by an using the given hand. /// /// Avatar to check /// Whether to check the left hand or right hand /// Returns the closest grabbable object or null if none was found /// Returns the grab point that can be grabbed /// List of grabbable objects to process or null to process all current enabled grabbable objects /// Whether a grabbable object was found public bool GetClosestGrabbableObject(UxrAvatar avatar, UxrHandSide handSide, out UxrGrabbableObject grabbableObject, out int grabPoint, IEnumerable candidates = null) { grabbableObject = null; grabPoint = 0; foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide) { return GetClosestGrabbableObject(grabber, out grabbableObject, out grabPoint, candidates); } } return false; } /// /// Gets the closest grabbable object that can be grabbed by a . /// /// Grabber to check /// Returns the closest grabbable object or null if none was found /// Returns the grab point that can be grabbed /// List of grabbable objects to process or null to process all current enabled grabbable objects /// Whether a grabbable object was found public bool GetClosestGrabbableObject(UxrGrabber grabber, out UxrGrabbableObject grabbableObject, out int grabPoint, IEnumerable candidates = null) { int maxPriority = int.MinValue; float minDistanceWithoutRotation = float.MaxValue; // Between different objects we don't take orientations into account grabbableObject = null; grabPoint = 0; // Iterate over objects foreach (UxrGrabbableObject candidate in candidates ?? UxrGrabbableObject.EnabledComponents) { float minDistance = float.MaxValue; // For the same object we will not just consider the distance but also how close the grabber is to the grip orientation // Iterate over grab points for (int point = 0; point < candidate.GrabPointCount; ++point) { if (candidate.CanBeGrabbedByGrabber(grabber, point)) { candidate.GetDistanceFromGrabber(grabber, point, out float distance, out float distanceWithoutRotation); if (candidate.Priority > maxPriority) { grabbableObject = candidate; grabPoint = point; minDistance = distance; minDistanceWithoutRotation = distanceWithoutRotation; maxPriority = candidate.Priority; } else if (candidate.Priority == maxPriority) { if ((grabbableObject == candidate && distance < minDistance) || (grabbableObject != candidate && distanceWithoutRotation < minDistanceWithoutRotation)) { grabbableObject = candidate; grabPoint = point; minDistance = distance; minDistanceWithoutRotation = distanceWithoutRotation; } } } } } return grabbableObject != null; } /// /// Gets whether grabbing a given using a certain will make /// the grabber's renderer show up as hidden due to the parameters set in the inspector. /// /// Grabber to check /// Grabbable object to check /// Whether the renderer would be hidden when grabbed public bool ShouldHideHandRenderer(UxrGrabber grabber, UxrGrabbableObject grabbableObject) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { int grabPoint = manipulationInfo.GetGrabbedPoint(grabber); if (grabPoint != -1) { return grabbableObject.GetGrabPoint(grabPoint).HideHandGrabberRenderer; } } return false; } /// /// Gets the grab pose name required when grabbing the given using the /// . /// /// Grabber /// Grabbable object /// Grab pose name or null to use the default grab pose specified in the avatar belonging to the grabber public string GetOverrideGrabPoseName(UxrGrabber grabber, UxrGrabbableObject grabbableObject) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { int grabPoint = manipulationInfo.GetGrabbedPoint(grabber); if (grabPoint != -1) { UxrHandPoseAsset handPoseAsset = grabbableObject.GetGrabPoint(grabPoint).GetGripPoseInfo(grabber.Avatar).HandPose; return handPoseAsset != null ? handPoseAsset.name : null; } } return null; } /// /// Gets the blend value for the pose used when grabbing the given /// using the . /// Blending is used to transition between different states such as open/closed or similar. /// /// Grabber /// Grabbable object /// Blending value [0.0, 1.0] public float GetOverrideGrabPoseBlendValue(UxrGrabber grabber, UxrGrabbableObject grabbableObject) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { int grabPoint = manipulationInfo.GetGrabbedPoint(grabber); if (grabPoint != -1) { return grabbableObject.GetGrabPoint(grabPoint).GetGripPoseInfo(grabber.Avatar).PoseBlendValue; } } return 0.0f; } /// /// Checks whether the given hand is currently grabbing something. /// /// Avatar to check /// Whether to check the left hand or right hand /// Whether it is currently grabbing something public bool IsHandGrabbing(UxrAvatar avatar, UxrHandSide handSide) { foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide && grabber.GrabbedObject != null) { return true; } } return false; } /// /// Checks if an avatar's hand is grabbing a grabbable object. /// /// Avatar to check /// Object to check if it is being grabbed /// Whether to check the left hand or right hand /// /// Whether to also check for any parent or child that /// is physically connected. /// /// Whether the object is being grabbed by the avatar using the given hand public bool IsHandGrabbing(UxrAvatar avatar, UxrGrabbableObject grabbableObject, UxrHandSide handSide, bool alsoCheckDependentGrab) { foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide && grabber.GrabbedObject != null) { // Grabbing directly with the hand if (grabber.GrabbedObject == grabbableObject) { return true; } if (alsoCheckDependentGrab) { // Grabbing a parent/child? if (GetParentsBeingGrabbedChain(grabber.GrabbedObject).Contains(grabbableObject) || GetChildrenBeingGrabbed(grabber.GrabbedObject).Contains(grabbableObject)) { return true; } } } } return false; } /// /// Gets all the objects currently being grabbed. /// /// Objects being grabbed public IEnumerator GetObjectsBeingGrabbed() { foreach (var manipulation in _currentManipulations) { yield return manipulation.Key; } } /// /// Gets the object being grabbed by an avatar. /// /// Avatar to get the grabbed object of /// Whether to check the left hand or right hand /// Returns the object being grabbed, or null if not found /// Whether there is an object being grabbed by the avatar using the given hand public bool GetObjectBeingGrabbed(UxrAvatar avatar, UxrHandSide handSide, out UxrGrabbableObject grabbableObject) { grabbableObject = null; foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar)) { if (grabber.Side == handSide && grabber.GrabbedObject != null) { grabbableObject = grabber.GrabbedObject; return true; } } return false; } /// /// Gets the number of hands currently grabbing an object. /// /// The grabbable object /// /// Also checks for hands that are grabbing other child objects that also control the direction of the given parent /// object. /// /// Number of hands grabbing the object public int GetHandsGrabbingCount(UxrGrabbableObject grabbableObject, bool alsoCheckDependentGrabs = true) { int result = 0; foreach (UxrGrabber grabber in UxrGrabber.EnabledComponents) { if (grabber.GrabbedObject != null) { // Grabbing directly with the hand if (grabber.GrabbedObject == grabbableObject) { result++; } else if (alsoCheckDependentGrabs) { // Grabbing a dependent grabbable? if (GetParentsBeingGrabbedChain(grabber.GrabbedObject).Contains(grabbableObject) || GetChildrenBeingGrabbed(grabber.GrabbedObject).Contains(grabbableObject)) { result++; } } } } return result; } /// /// Checks whether the given grabbable object is being grabbed. /// /// The grabbable object /// Whether it is being grabbed public bool IsBeingGrabbed(UxrGrabbableObject grabbableObject) { return _currentManipulations != null && grabbableObject != null && _currentManipulations.ContainsKey(grabbableObject); } /// /// Checks whether the given grabbable object is being grabbed using the given grab point. /// /// The grabbable object /// Grab point of the grabbable object to check /// Whether the grab point is being grabbed using the given grab point public bool IsBeingGrabbed(UxrGrabbableObject grabbableObject, int point) { if (_currentManipulations == null || grabbableObject == null) { return false; } return _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.GrabbedPoints.Contains(point); } /// /// Checks whether the given grabbable object is being grabbed by an avatar. /// /// The grabbable object /// The avatar to check /// Whether it is being grabbed by the avatar public bool IsBeingGrabbedBy(UxrGrabbableObject grabbableObject, UxrAvatar avatar) { if (_currentManipulations == null || grabbableObject == null) { return false; } return _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.Grabbers.Any(grabber => grabber.Avatar == avatar); } /// /// Checks whether the given grabbable object is being grabbed by a specific grabber. /// /// The grabbable object /// The grabber to check /// Whether it is being grabbed by the given grabber public bool IsBeingGrabbedBy(UxrGrabbableObject grabbableObject, UxrGrabber grabber) { if (_currentManipulations == null || grabbableObject == null) { return false; } return _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.Grabbers.Any(grb => grabber == grb); } /// /// Checks whether the given grabbable object is being grabbed using any other grab point than the specified. /// /// The grabbable object /// Grab point of the grabbable object not to check /// Whether any other grab point is being grabbed public bool IsBeingGrabbedByOtherThan(UxrGrabbableObject grabbableObject, int point) { if (_currentManipulations == null || grabbableObject == null) { return false; } return _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.GrabbedPoints.Any(grabPoint => point != grabPoint); } /// /// Checks whether the given grabbable object is being grabbed using any other grab point and any other grabber than /// the specified. /// /// The grabbable object /// Point should be any other than this /// Grabber should be any other than this /// Whether the object is being grabbed with the specified conditions public bool IsBeingGrabbedByOtherThan(UxrGrabbableObject grabbableObject, int point, UxrGrabber grabber) { if (_currentManipulations == null || grabbableObject == null) { return false; } if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { foreach (RuntimeGrabInfo grabInfo in manipulationInfo.Grabs) { if (grabInfo.Grabber != grabber || grabInfo.GrabbedPoint != point) { return true; } } } return false; } /// /// Gets the hands that are grabbing an object. /// /// The grabbable object /// Whether it is being grabbed using the left hand /// Whether it is being grabbed using the right hand /// Whether it is being grabbed public bool GetGrabbingHand(UxrGrabbableObject grabbableObject, out bool isLeft, out bool isRight) { isLeft = false; isRight = false; foreach (UxrGrabber grabber in UxrGrabber.EnabledComponents) { if (grabber.GrabbedObject == grabbableObject) { if (grabber.Side == UxrHandSide.Left) { isLeft = true; } else { isRight = true; } } } return isLeft || isRight; } /// /// Gets the grabber that is grabbing an object using a specific grab point. /// /// The grabbable object /// Grab point to check /// Grabber to check /// Whether it is being grabbed with the specified conditions public bool GetGrabbingHand(UxrGrabbableObject grabbableObject, int point, out UxrGrabber grabber) { grabber = null; foreach (UxrGrabber grabberCandidate in UxrGrabber.EnabledComponents) { if (grabberCandidate.GrabbedObject == grabbableObject) { foreach (RuntimeGrabInfo grabInfo in GetGrabs(grabbableObject)) { if (grabInfo.GrabbedPoint == point) { grabber = grabInfo.Grabber; return true; } } } } return false; } /// /// Gets the hand grabbing the given object using a given grab point. /// /// The grabbable object /// The grab point used to grab the object /// Returns the hand that is used to grab the object /// Whether there is a hand grabbing the object public bool GetGrabbingHand(UxrGrabbableObject grabbableObject, int point, out UxrHandSide handSide) { handSide = UxrHandSide.Left; if (GetGrabbingHand(grabbableObject, point, out UxrGrabber grabber)) { handSide = grabber.Side; return true; } return false; } /// /// Gets the grabbers that are grabbing the object using a specific grab point. /// /// The grabbable object /// The grab point or -1 to get all grabbed points /// /// Returns the list of grabbers. If the list is null a new list is created, otherwise the grabbers /// are added to the list. /// /// Whether one or more grabbers were found public bool GetGrabbingHands(UxrGrabbableObject grabbableObject, int point, out List grabbers) { grabbers = null; foreach (RuntimeGrabInfo grabInfo in GetGrabs(grabbableObject)) { if (grabInfo.GrabbedPoint == point || point == -1) { grabbers ??= new List(); if (!grabbers.Contains(grabInfo.Grabber)) { grabbers.Add(grabInfo.Grabber); } } } return grabbers != null && grabbers.Count > 0; } /// /// Gets the grabbers that are grabbing the object using a specific grab point. /// /// The grabbable object /// The grab point or -1 to get all grabbed points /// List of grabbers public IEnumerable GetGrabbingHands(UxrGrabbableObject grabbableObject, int point = -1) { foreach (RuntimeGrabInfo grabInfo in GetGrabs(grabbableObject)) { if (grabInfo.GrabbedPoint == point || point == -1) { yield return grabInfo.Grabber; } } } /// /// Gets the grab point that the is currently grabbing on a /// . /// /// Grabber to get the grabbed point from /// Grab point index that is being grabbed or -1 if there is no object currently being grabbed public int GetGrabbedPoint(UxrGrabber grabber) { if (grabber && grabber.GrabbedObject != null && _currentManipulations.TryGetValue(grabber.GrabbedObject, out RuntimeManipulationInfo manipulationInfo)) { foreach (RuntimeGrabInfo grabInfo in manipulationInfo.Grabs) { if (grabInfo.Grabber == grabber) { return grabInfo.GrabbedPoint; } } } return -1; } /// /// Gets the number of grab points that are currently being grabbed from a . /// /// Grabbable object /// Number of grab points being grabbed public int GetGrabbedPointCount(UxrGrabbableObject grabbableObject) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { return manipulationInfo.Grabs.Count; } return 0; } /// /// Gets the number of hands that are grabbing the given object. /// /// Grabbable object /// Whether to also count dependent child grabbable objects that are being grabbed /// Number of hands grabbing the object public int GetGrabbingHandCount(UxrGrabbableObject grabbableObject, bool includeChildGrabs = true) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { return manipulationInfo.Grabs.Count + (includeChildGrabs ? GetChildrenBeingGrabbed(grabbableObject).Count() : 0); } return 0; } /// /// Gets the where the given was grabbed /// from. /// /// Grabbable object /// Anchor the grabbable object was grabbed from public UxrGrabbableObjectAnchor GetGrabbedObjectAnchorFrom(UxrGrabbableObject grabbableObject) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { return manipulationInfo.SourceAnchor; } return null; } /// /// Gets the current world-space velocity, in units per second, of an object that is being grabbed. /// /// Grabbable object /// Whether to smooth the velocity using a previous frame data window for improved behavior /// Velocity in world-space units per second public Vector3 GetGrabbedObjectVelocity(UxrGrabbableObject grabbableObject, bool smooth = true) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.Grabs.Any()) { return smooth ? manipulationInfo.Grabs[0].Grabber.SmoothVelocity : manipulationInfo.Grabs[0].Grabber.Velocity; } return Vector3.zero; } /// /// Gets the current world-space angular velocity, in degrees per second, of an object that is being grabbed. /// /// Grabbable object /// Whether to smooth the velocity using a previous frame data window for improved behavior /// Angular velocity in world-space euler angle degrees per second public Vector3 GetGrabbedObjectAngularVelocity(UxrGrabbableObject grabbableObject, bool smooth = true) { if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo) && manipulationInfo.Grabs.Any()) { return smooth ? manipulationInfo.Grabs[0].Grabber.SmoothAngularVelocity : manipulationInfo.Grabs[0].Grabber.AngularVelocity; } return Vector3.zero; } #endregion #region Private Methods /// /// Tries to get the grab information of a specific . /// /// Grabber to get the grab information from /// Returns the grab information /// True if successful, false if the grabber is not valid or isn't grabbing any object private bool TryGetGrabInfo(UxrGrabber grabber, out RuntimeGrabInfo grabInfo) { grabInfo = null; if (grabber && grabber.GrabbedObject && _currentManipulations.TryGetValue(grabber.GrabbedObject, out RuntimeManipulationInfo manipulationInfo)) { grabInfo = manipulationInfo.GetGrabInfo(grabber); return true; } return false; } /// /// Enumerates all grabs on the given grabbable object. /// /// Grabbable object to get the grab information from /// List of grabs private IEnumerable GetGrabs(UxrGrabbableObject grabbableObject) { if (grabbableObject != null && _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo)) { foreach (RuntimeGrabInfo grabInfo in manipulationInfo.Grabs) { yield return grabInfo; } } } /// /// Gets the parent being grabbed of a given . /// /// Grabbable object /// Parent that is being grabbed or null if there isn't any private UxrGrabbableObject GetParentBeingGrabbed(UxrGrabbableObject grabbableObject) { if (grabbableObject != null && grabbableObject.transform.parent != null) { UxrGrabbableObject parentGrabbableObject = grabbableObject.transform.parent.GetComponentInParent(); if (parentGrabbableObject != null) { if (IsBeingGrabbed(parentGrabbableObject)) { return parentGrabbableObject; } return GetParentBeingGrabbed(parentGrabbableObject); } } return null; } /// /// Gets the chain of parents of a given that are being grabbed in bottom to top /// hierarchical order. /// /// Grabbable object /// Chain of parents being grabbed in bottom to top hierarchical order private IEnumerable GetParentsBeingGrabbedChain(UxrGrabbableObject grabbableObject) { UxrGrabbableObject current = grabbableObject; while (current != null) { current = GetParentBeingGrabbed(current); if (current != null) { yield return current; } } } /// /// Gets a 's list of children being grabbed. /// /// Grabbable object /// List of children that are being grabbed private IEnumerable GetChildrenBeingGrabbed(UxrGrabbableObject grabbableObject) { if (grabbableObject == null) { yield break; } foreach (UxrGrabbableObject child in grabbableObject.AllChildren) { if (child != grabbableObject && _currentManipulations.ContainsKey(child)) { yield return child; } } } /// /// Gets a 's list of direct grabbable children that are being grabbed /// and control the direction of the grabbable object. /// /// Grabbable object /// List of direct grabbable children that are being grabbed and control the grabbable object direction private IEnumerable GetDirectChildrenLookAtBeingGrabbed(UxrGrabbableObject grabbableObject) { foreach (RuntimeManipulationInfo childManipulation in GetDirectChildrenLookAtManipulations(grabbableObject)) { yield return childManipulation.GrabbableObject; } } /// /// Gets a 's list of direct grabbable children manipulations that /// control the direction of the grabbable object. /// /// Grabbable object /// /// List of manipulations of direct grabbable children that are being grabbed and control the grabbable object /// direction /// private IEnumerable GetDirectChildrenLookAtManipulations(UxrGrabbableObject grabbableObject) { if (grabbableObject == null) { yield break; } foreach (UxrGrabbableObject child in grabbableObject.DirectChildrenLookAts) { if (_currentManipulations.TryGetValue(child, out RuntimeManipulationInfo childManipulationInfo)) { yield return childManipulationInfo; } } } /// /// Gets the world-space snap position of a given grabbing the object. /// Depending on the object's snap settings, this will be the grab point snap position (either /// object to hand or hand to object) or the same grip position relative to the object when the /// grab was performed. /// /// Grabber to get the snap position of /// Snap position or if the grabber isn't currently grabbing an object private Vector3 GetGrabbedPointGrabAlignPosition(UxrGrabber grabber) { if (grabber.GrabbedObject == null || !_currentManipulations.TryGetValue(grabber.GrabbedObject, out RuntimeManipulationInfo manipulationInfo) || !TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return Vector3.zero; } if (grabber.GrabbedObject.GetGrabPointSnapModeAffectsPosition(manipulationInfo.GetGrabbedPoint(grabber), UxrHandSnapDirection.ObjectToHand)) { // Snap to grab point so that object goes to hand return TransformExt.GetWorldPosition(grabInfo.GrabAlignParentTransformUsed, grabInfo.RelativeGrabAlignPosition); } if (grabber.GrabbedObject.GetGrabPointSnapModeAffectsPosition(manipulationInfo.GetGrabbedPoint(grabber), UxrHandSnapDirection.HandToObject)) { // Snap to grab point so that hand goes to object Transform snapTransform = grabber.GrabbedObject.GetGrabPointGrabAlignTransform(grabber.Avatar, manipulationInfo.GetGrabbedPoint(grabber), grabber.Side); return snapTransform.TransformPoint(grabInfo.RelativeUsedGrabAlignPosition); } // Keep same grip position relative to the object as when it was grabbed return grabber.GrabbedObject.transform.TransformPoint(GetGrabPointRelativeGrabberPosition(grabber)); } /// /// Gets the world-space snap rotation of a given grabbing the object. /// Depending on the object's snap settings, this will be the grab point snap rotation (either /// object to hand or hand to object) or the same grip rotation relative to the object when the /// grab was performed. /// /// Grabber to get the snap rotation of /// Snap rotation or if the grabber isn't currently grabbing an object private Quaternion GetGrabbedPointGrabAlignRotation(UxrGrabber grabber) { if (grabber.GrabbedObject == null || !_currentManipulations.TryGetValue(grabber.GrabbedObject, out RuntimeManipulationInfo manipulationInfo) || !TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return Quaternion.identity; } if (grabber.GrabbedObject.GetGrabPointSnapModeAffectsRotation(manipulationInfo.GetGrabbedPoint(grabber), UxrHandSnapDirection.ObjectToHand)) { // Snap to grab point so that object rotates to hand return TransformExt.GetWorldRotation(grabInfo.GrabAlignParentTransformUsed, grabInfo.RelativeGrabAlignRotation); } if (grabber.GrabbedObject.GetGrabPointSnapModeAffectsRotation(manipulationInfo.GetGrabbedPoint(grabber), UxrHandSnapDirection.HandToObject)) { // Snap to grab point so that hand rotates to object Transform snapTransform = grabber.GrabbedObject.GetGrabPointGrabAlignTransform(grabber.Avatar, manipulationInfo.GetGrabbedPoint(grabber), grabber.Side); return snapTransform.rotation * grabInfo.RelativeUsedGrabAlignRotation; } // Keep same grip rotation relative to the object as when it was grabbed return grabber.GrabbedObject.transform.rotation * GetGrabPointRelativeGrabberRotation(grabber); } /// /// Gets the position that is used to compute proximity from a to the grabbed point. /// /// Grabber to get the proximity point for /// /// Position required to compute the proximity to or if the grabber isn't currently /// grabbing an object /// private Vector3 GetGrabbedPointGrabProximityPosition(UxrGrabber grabber) { if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return grabber.GrabbedObject.transform.TransformPoint(grabInfo.RelativeProximityPosition); } return Vector3.zero; } /// /// Gets the relative position of the object to the grabber at the time it was grabbed. /// /// Grabber with the object being grabbed /// /// Relative position or if the grabber isn't currently grabbing an object. /// private Vector3 GetGrabPointRelativeGrabPosition(UxrGrabber grabber) { if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return grabInfo.RelativeGrabPosition; } return Vector3.zero; } /// /// Gets the relative rotation of the object to the grabber at the time it was grabbed. /// /// Grabber with the object being grabbed /// /// Relative rotation or if the grabber isn't currently grabbing an object. /// private Quaternion GetGrabPointRelativeGrabRotation(UxrGrabber grabber) { if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return grabInfo.RelativeGrabRotation; } return Quaternion.identity; } /// /// Gets the relative position of the grabber to the object it is grabbing at the time it was grabbed. /// /// Grabber with the object being grabbed /// /// Relative position or if the grabber isn't currently grabbing an object. /// private Vector3 GetGrabPointRelativeGrabberPosition(UxrGrabber grabber) { if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return grabInfo.RelativeGrabberPosition; } return Vector3.zero; } /// /// Gets the relative rotation of the grabber to the object it is grabbing at the time it was grabbed. /// /// Grabber with the object being grabbed /// /// Relative rotation or if the grabber isn't currently grabbing an object. /// private Quaternion GetGrabPointRelativeGrabberRotation(UxrGrabber grabber) { if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo)) { return grabInfo.RelativeGrabberRotation; } return Quaternion.identity; } #endregion } }