Files
dungeons/Assets/UltimateXR/Runtime/Scripts/Manipulation/UxrGrabManager.Querying.cs
2024-08-06 21:58:35 +02:00

988 lines
44 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrGrabManager.Querying.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
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
/// <summary>
/// Checks whether an <see cref="UxrAvatar" /> can grab something using the given hand.
/// </summary>
/// <param name="avatar">Avatar to check</param>
/// <param name="handSide">Whether to check the left or right hand</param>
/// <returns>Whether something can be grabbed</returns>
public bool CanGrabSomething(UxrAvatar avatar, UxrHandSide handSide)
{
foreach (UxrGrabber grabber in UxrGrabber.GetComponents(avatar))
{
if (grabber.Side == handSide)
{
return CanGrabSomething(grabber);
}
}
return false;
}
/// <summary>
/// Checks whether a <see cref="UxrGrabber" /> can grab something using the given grabber.
/// </summary>
/// <param name="grabber">Grabber to check</param>
/// <returns>Whether something can be grabbed</returns>
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;
}
/// <summary>
/// Gets the closest grabbable object that can be grabbed by an <see cref="UxrAvatar" /> using the given hand.
/// </summary>
/// <param name="avatar">Avatar to check</param>
/// <param name="handSide">Whether to check the left hand or right hand</param>
/// <param name="grabbableObject">Returns the closest grabbable object or null if none was found</param>
/// <returns>Whether a grabbable object was found</returns>
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;
}
/// <summary>
/// Gets the closest grabbable object that can be grabbed by an <see cref="UxrAvatar" /> using the given hand.
/// </summary>
/// <param name="avatar">Avatar to check</param>
/// <param name="handSide">Whether to check the left hand or right hand</param>
/// <param name="grabbableObject">Returns the closest grabbable object or null if none was found</param>
/// <param name="grabPoint">Returns the grab point that can be grabbed</param>
/// <param name="candidates">List of grabbable objects to process or null to process all current enabled grabbable objects</param>
/// <returns>Whether a grabbable object was found</returns>
public bool GetClosestGrabbableObject(UxrAvatar avatar, UxrHandSide handSide, out UxrGrabbableObject grabbableObject, out int grabPoint, IEnumerable<UxrGrabbableObject> 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;
}
/// <summary>
/// Gets the closest grabbable object that can be grabbed by a <see cref="UxrGrabber" />.
/// </summary>
/// <param name="grabber">Grabber to check</param>
/// <param name="grabbableObject">Returns the closest grabbable object or null if none was found</param>
/// <param name="grabPoint">Returns the grab point that can be grabbed</param>
/// <param name="candidates">List of grabbable objects to process or null to process all current enabled grabbable objects</param>
/// <returns>Whether a grabbable object was found</returns>
public bool GetClosestGrabbableObject(UxrGrabber grabber, out UxrGrabbableObject grabbableObject, out int grabPoint, IEnumerable<UxrGrabbableObject> 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;
}
/// <summary>
/// Gets whether grabbing a given <see cref="UxrGrabbableObject" /> using a certain <see cref="UxrGrabber" /> will make
/// the grabber's renderer show up as hidden due to the parameters set in the inspector.
/// </summary>
/// <param name="grabber">Grabber to check</param>
/// <param name="grabbableObject">Grabbable object to check</param>
/// <returns>Whether the renderer would be hidden when grabbed</returns>
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;
}
/// <summary>
/// Gets the grab pose name required when grabbing the given <see cref="UxrGrabbableObject" /> using the
/// <see cref="UxrGrabber" />.
/// </summary>
/// <param name="grabber">Grabber</param>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Grab pose name or null to use the default grab pose specified in the avatar belonging to the grabber</returns>
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;
}
/// <summary>
/// Gets the blend value for the <see cref="UxrHandPoseType.Blend" /> pose used when grabbing the given
/// <see cref="UxrGrabbableObject" /> using the <see cref="UxrGrabber" />.
/// Blending is used to transition between different states such as open/closed or similar.
/// </summary>
/// <param name="grabber">Grabber</param>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Blending value [0.0, 1.0]</returns>
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;
}
/// <summary>
/// Checks whether the given <see cref="UxrAvatar" /> hand is currently grabbing something.
/// </summary>
/// <param name="avatar">Avatar to check</param>
/// <param name="handSide">Whether to check the left hand or right hand</param>
/// <returns>Whether it is currently grabbing something</returns>
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;
}
/// <summary>
/// Checks if an avatar's hand is grabbing a grabbable object.
/// </summary>
/// <param name="avatar">Avatar to check</param>
/// <param name="grabbableObject">Object to check if it is being grabbed</param>
/// <param name="handSide">Whether to check the left hand or right hand</param>
/// <param name="alsoCheckDependentGrab">
/// Whether to also check for any parent or child <see cref="UxrGrabbableObject" /> that
/// is physically connected.
/// </param>
/// <returns>Whether the object is being grabbed by the avatar using the given hand</returns>
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;
}
/// <summary>
/// Gets all the objects currently being grabbed.
/// </summary>
/// <returns>Objects being grabbed</returns>
public IEnumerator<UxrGrabbableObject> GetObjectsBeingGrabbed()
{
foreach (var manipulation in _currentManipulations)
{
yield return manipulation.Key;
}
}
/// <summary>
/// Gets the object being grabbed by an avatar.
/// </summary>
/// <param name="avatar">Avatar to get the grabbed object of</param>
/// <param name="handSide">Whether to check the left hand or right hand</param>
/// <param name="grabbableObject">Returns the object being grabbed, or null if not found</param>
/// <returns>Whether there is an object being grabbed by the avatar using the given hand</returns>
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;
}
/// <summary>
/// Gets the number of hands currently grabbing an object.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="alsoCheckDependentGrabs">
/// Also checks for hands that are grabbing other child objects that also control the direction of the given parent
/// object.
/// </param>
/// <returns>Number of hands grabbing the object</returns>
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;
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <returns>Whether it is being grabbed</returns>
public bool IsBeingGrabbed(UxrGrabbableObject grabbableObject)
{
return _currentManipulations != null && grabbableObject != null && _currentManipulations.ContainsKey(grabbableObject);
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed using the given grab point.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">Grab point of the grabbable object to check</param>
/// <returns>Whether the grab point is being grabbed using the given grab point</returns>
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);
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed by an avatar.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="avatar">The avatar to check</param>
/// <returns>Whether it is being grabbed by the avatar</returns>
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);
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed by a specific grabber.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="grabber">The grabber to check</param>
/// <returns>Whether it is being grabbed by the given grabber</returns>
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);
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed using any other grab point than the specified.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">Grab point of the grabbable object not to check</param>
/// <returns>Whether any other grab point is being grabbed</returns>
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);
}
/// <summary>
/// Checks whether the given grabbable object is being grabbed using any other grab point and any other grabber than
/// the specified.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">Point should be any other than this</param>
/// <param name="grabber">Grabber should be any other than this</param>
/// <returns>Whether the object is being grabbed with the specified conditions</returns>
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;
}
/// <summary>
/// Gets the hands that are grabbing an object.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="isLeft">Whether it is being grabbed using the left hand</param>
/// <param name="isRight">Whether it is being grabbed using the right hand</param>
/// <returns>Whether it is being grabbed</returns>
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;
}
/// <summary>
/// Gets the grabber that is grabbing an object using a specific grab point.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">Grab point to check</param>
/// <param name="grabber">Grabber to check</param>
/// <returns>Whether it is being grabbed with the specified conditions</returns>
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;
}
/// <summary>
/// Gets the hand grabbing the given object using a given grab point.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">The grab point used to grab the object</param>
/// <param name="handSide">Returns the hand that is used to grab the object</param>
/// <returns>Whether there is a hand grabbing the object</returns>
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;
}
/// <summary>
/// Gets the grabbers that are grabbing the object using a specific grab point.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">The grab point or -1 to get all grabbed points</param>
/// <param name="grabbers">
/// Returns the list of grabbers. If the list is null a new list is created, otherwise the grabbers
/// are added to the list.
/// </param>
/// <returns>Whether one or more grabbers were found</returns>
public bool GetGrabbingHands(UxrGrabbableObject grabbableObject, int point, out List<UxrGrabber> grabbers)
{
grabbers = null;
foreach (RuntimeGrabInfo grabInfo in GetGrabs(grabbableObject))
{
if (grabInfo.GrabbedPoint == point || point == -1)
{
grabbers ??= new List<UxrGrabber>();
if (!grabbers.Contains(grabInfo.Grabber))
{
grabbers.Add(grabInfo.Grabber);
}
}
}
return grabbers != null && grabbers.Count > 0;
}
/// <summary>
/// Gets the grabbers that are grabbing the object using a specific grab point.
/// </summary>
/// <param name="grabbableObject">The grabbable object</param>
/// <param name="point">The grab point or -1 to get all grabbed points</param>
/// <returns>List of grabbers</returns>
public IEnumerable<UxrGrabber> GetGrabbingHands(UxrGrabbableObject grabbableObject, int point = -1)
{
foreach (RuntimeGrabInfo grabInfo in GetGrabs(grabbableObject))
{
if (grabInfo.GrabbedPoint == point || point == -1)
{
yield return grabInfo.Grabber;
}
}
}
/// <summary>
/// Gets the grab point that the <see cref="UxrGrabber" /> is currently grabbing on a <see cref="UxrGrabbableObject" />
/// .
/// </summary>
/// <param name="grabber">Grabber to get the grabbed point from</param>
/// <returns>Grab point index that is being grabbed or -1 if there is no object currently being grabbed</returns>
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;
}
/// <summary>
/// Gets the number of grab points that are currently being grabbed from a <see cref="UxrGrabbableObject" />.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Number of grab points being grabbed</returns>
public int GetGrabbedPointCount(UxrGrabbableObject grabbableObject)
{
if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo))
{
return manipulationInfo.Grabs.Count;
}
return 0;
}
/// <summary>
/// Gets the number of hands that are grabbing the given object.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <param name="includeChildGrabs">Whether to also count dependent child grabbable objects that are being grabbed</param>
/// <returns>Number of hands grabbing the object</returns>
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;
}
/// <summary>
/// Gets the <see cref="UxrGrabbableObjectAnchor" /> where the given <see cref="UxrGrabbableObject" /> was grabbed
/// from.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Anchor the grabbable object was grabbed from</returns>
public UxrGrabbableObjectAnchor GetGrabbedObjectAnchorFrom(UxrGrabbableObject grabbableObject)
{
if (_currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo))
{
return manipulationInfo.SourceAnchor;
}
return null;
}
/// <summary>
/// Gets the current world-space velocity, in units per second, of an object that is being grabbed.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <param name="smooth">Whether to smooth the velocity using a previous frame data window for improved behavior</param>
/// <returns>Velocity in world-space units per second</returns>
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;
}
/// <summary>
/// Gets the current world-space angular velocity, in degrees per second, of an object that is being grabbed.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <param name="smooth">Whether to smooth the velocity using a previous frame data window for improved behavior</param>
/// <returns>Angular velocity in world-space euler angle degrees per second</returns>
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
/// <summary>
/// Tries to get the grab information of a specific <see cref="UxrGrabber" />.
/// </summary>
/// <param name="grabber">Grabber to get the grab information from</param>
/// <param name="grabInfo">Returns the grab information</param>
/// <returns>True if successful, false if the grabber is not valid or isn't grabbing any object</returns>
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;
}
/// <summary>
/// Enumerates all grabs on the given grabbable object.
/// </summary>
/// <param name="grabbableObject">Grabbable object to get the grab information from</param>
/// <returns>List of grabs</returns>
private IEnumerable<RuntimeGrabInfo> GetGrabs(UxrGrabbableObject grabbableObject)
{
if (grabbableObject != null && _currentManipulations.TryGetValue(grabbableObject, out RuntimeManipulationInfo manipulationInfo))
{
foreach (RuntimeGrabInfo grabInfo in manipulationInfo.Grabs)
{
yield return grabInfo;
}
}
}
/// <summary>
/// Gets the parent being grabbed of a given <see cref="UxrGrabbableObject" />.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Parent <see cref="UxrGrabbableObject" /> that is being grabbed or null if there isn't any</returns>
private UxrGrabbableObject GetParentBeingGrabbed(UxrGrabbableObject grabbableObject)
{
if (grabbableObject != null && grabbableObject.transform.parent != null)
{
UxrGrabbableObject parentGrabbableObject = grabbableObject.transform.parent.GetComponentInParent<UxrGrabbableObject>();
if (parentGrabbableObject != null)
{
if (IsBeingGrabbed(parentGrabbableObject))
{
return parentGrabbableObject;
}
return GetParentBeingGrabbed(parentGrabbableObject);
}
}
return null;
}
/// <summary>
/// Gets the chain of parents of a given <see cref="UxrGrabbableObject" /> that are being grabbed in bottom to top
/// hierarchical order.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>Chain of parents being grabbed in bottom to top hierarchical order</returns>
private IEnumerable<UxrGrabbableObject> GetParentsBeingGrabbedChain(UxrGrabbableObject grabbableObject)
{
UxrGrabbableObject current = grabbableObject;
while (current != null)
{
current = GetParentBeingGrabbed(current);
if (current != null)
{
yield return current;
}
}
}
/// <summary>
/// Gets a <see cref="UxrGrabbableObject" />'s list of children being grabbed.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>List of children that are being grabbed</returns>
private IEnumerable<UxrGrabbableObject> GetChildrenBeingGrabbed(UxrGrabbableObject grabbableObject)
{
if (grabbableObject == null)
{
yield break;
}
foreach (UxrGrabbableObject child in grabbableObject.AllChildren)
{
if (child != grabbableObject && _currentManipulations.ContainsKey(child))
{
yield return child;
}
}
}
/// <summary>
/// Gets a <see cref="UxrGrabbableObject" />'s list of direct grabbable children that are being grabbed
/// and control the direction of the grabbable object.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>List of direct grabbable children that are being grabbed and control the grabbable object direction</returns>
private IEnumerable<UxrGrabbableObject> GetDirectChildrenLookAtBeingGrabbed(UxrGrabbableObject grabbableObject)
{
foreach (RuntimeManipulationInfo childManipulation in GetDirectChildrenLookAtManipulations(grabbableObject))
{
yield return childManipulation.GrabbableObject;
}
}
/// <summary>
/// Gets a <see cref="UxrGrabbableObject" />'s list of direct grabbable children manipulations that
/// control the direction of the grabbable object.
/// </summary>
/// <param name="grabbableObject">Grabbable object</param>
/// <returns>
/// List of manipulations of direct grabbable children that are being grabbed and control the grabbable object
/// direction
/// </returns>
private IEnumerable<RuntimeManipulationInfo> GetDirectChildrenLookAtManipulations(UxrGrabbableObject grabbableObject)
{
if (grabbableObject == null)
{
yield break;
}
foreach (UxrGrabbableObject child in grabbableObject.DirectChildrenLookAts)
{
if (_currentManipulations.TryGetValue(child, out RuntimeManipulationInfo childManipulationInfo))
{
yield return childManipulationInfo;
}
}
}
/// <summary>
/// Gets the world-space snap position of a given <see cref="UxrGrabber" /> 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.
/// </summary>
/// <param name="grabber">Grabber to get the snap position of</param>
/// <returns>Snap position or <see cref="Vector3.zero" /> if the grabber isn't currently grabbing an object</returns>
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));
}
/// <summary>
/// Gets the world-space snap rotation of a given <see cref="UxrGrabber" /> 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.
/// </summary>
/// <param name="grabber">Grabber to get the snap rotation of</param>
/// <returns>Snap rotation or <see cref="Quaternion.identity" /> if the grabber isn't currently grabbing an object</returns>
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);
}
/// <summary>
/// Gets the position that is used to compute proximity from a <see cref="UxrGrabber" /> to the grabbed point.
/// </summary>
/// <param name="grabber">Grabber to get the proximity point for</param>
/// <returns>
/// Position required to compute the proximity to or <see cref="Vector3.zero" /> if the grabber isn't currently
/// grabbing an object
/// </returns>
private Vector3 GetGrabbedPointGrabProximityPosition(UxrGrabber grabber)
{
if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo))
{
return grabber.GrabbedObject.transform.TransformPoint(grabInfo.RelativeProximityPosition);
}
return Vector3.zero;
}
/// <summary>
/// Gets the relative position of the object to the grabber at the time it was grabbed.
/// </summary>
/// <param name="grabber">Grabber with the object being grabbed</param>
/// <returns>
/// Relative position or <see cref="Vector3.zero" /> if the grabber isn't currently grabbing an object.
/// </returns>
private Vector3 GetGrabPointRelativeGrabPosition(UxrGrabber grabber)
{
if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo))
{
return grabInfo.RelativeGrabPosition;
}
return Vector3.zero;
}
/// <summary>
/// Gets the relative rotation of the object to the grabber at the time it was grabbed.
/// </summary>
/// <param name="grabber">Grabber with the object being grabbed</param>
/// <returns>
/// Relative rotation or <see cref="Quaternion.identity" /> if the grabber isn't currently grabbing an object.
/// </returns>
private Quaternion GetGrabPointRelativeGrabRotation(UxrGrabber grabber)
{
if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo))
{
return grabInfo.RelativeGrabRotation;
}
return Quaternion.identity;
}
/// <summary>
/// Gets the relative position of the grabber to the object it is grabbing at the time it was grabbed.
/// </summary>
/// <param name="grabber">Grabber with the object being grabbed</param>
/// <returns>
/// Relative position or <see cref="Vector3.zero" /> if the grabber isn't currently grabbing an object.
/// </returns>
private Vector3 GetGrabPointRelativeGrabberPosition(UxrGrabber grabber)
{
if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo))
{
return grabInfo.RelativeGrabberPosition;
}
return Vector3.zero;
}
/// <summary>
/// Gets the relative rotation of the grabber to the object it is grabbing at the time it was grabbed.
/// </summary>
/// <param name="grabber">Grabber with the object being grabbed</param>
/// <returns>
/// Relative rotation or <see cref="Quaternion.identity" /> if the grabber isn't currently grabbing an object.
/// </returns>
private Quaternion GetGrabPointRelativeGrabberRotation(UxrGrabber grabber)
{
if (TryGetGrabInfo(grabber, out RuntimeGrabInfo grabInfo))
{
return grabInfo.RelativeGrabberRotation;
}
return Quaternion.identity;
}
#endregion
}
}