// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using UltimateXR.Avatar; using UltimateXR.Core; using UltimateXR.Devices; using UnityEngine; namespace UltimateXR.Manipulation { /// /// Defines a grab point. A grab point describes a point of an object which /// can be grabbed. Objects can have multiple grab points to allow it to be grabbed from different angles. /// Grab points can be further expanded by using a , which gives flexibility /// by allowing it to be grabbed around or along an axis passing through that point, for example. /// [Serializable] public class UxrGrabPointInfo { #region Inspector Properties/Serialized Fields [SerializeField] private bool _editorFoldout = true; [SerializeField] private string _editorName = ""; [SerializeField] private UxrGrabMode _grabMode = UxrGrabMode.GrabWhilePressed; [SerializeField] private bool _useDefaultGrabButtons = true; [SerializeField] private bool _bothHandsCompatible = true; [SerializeField] private UxrHandSide _handSide = UxrHandSide.Left; [SerializeField] private UxrInputButtons _inputButtons = UxrInputButtons.Grip; [SerializeField] private bool _hideHandGrabberRenderer; [SerializeField] private UxrGripPoseInfo _defaultGripPoseInfo = new UxrGripPoseInfo(null); [SerializeField] private UxrSnapToHandMode _snapMode = UxrSnapToHandMode.PositionAndRotation; [SerializeField] private UxrHandSnapDirection _snapDirection = UxrHandSnapDirection.ObjectToHand; [SerializeField] private UxrSnapReference _snapReference = UxrSnapReference.UseOtherTransform; [SerializeField] private List _avatarGripPoseEntries = new List(); [SerializeField] private bool _alignToController; [SerializeField] private Transform _alignToControllerAxes; [SerializeField] private UxrGrabProximityMode _grabProximityMode = UxrGrabProximityMode.UseProximity; [SerializeField] private BoxCollider _grabProximityBox; [SerializeField] private float _maxDistanceGrab = 0.2f; [SerializeField] private bool _grabProximityTransformUseSelf = true; [SerializeField] private Transform _grabProximityTransform; [SerializeField] private bool _grabberProximityUseDefault = true; [SerializeField] private int _grabberProximityIndex; [SerializeField] private GameObject _enableOnHandNear; #endregion #region Public Types & Data /// /// Gets the proximity index used to compute the distance to the object. -1 for default (the /// grabber itself) or any other value for additional transforms in the component. /// public int GrabberProximityTransformIndex => GrabberProximityUseDefault ? -1 : GrabberProximityIndex; /// /// Gets how many grip pose entries there are. 1 (the default grip pose info) plus all the registered avatar ones. /// public int GripPoseInfoCount => 1 + _avatarGripPoseEntries.Count; /// /// Gets the registered avatars for specific grip poses and properties. /// public List AvatarGripPoseEntries => _avatarGripPoseEntries; /// /// Gets or sets whether foldout control for a given grab point is folded out or not. We use this in the /// editor to check if we need to render the preview grab pose meshes for a given grab point. /// Grab points that are not folded out are not rendered. /// public bool IsEditorFoldedOut { get => _editorFoldout; set => _editorFoldout = value; } /// /// Gets or sets the grab point display name in the inspector. /// public string EditorName { get => _editorName; set => _editorName = value; } /// /// Gets or sets the grab mode. /// public UxrGrabMode GrabMode { get => _grabMode; set => _grabMode = value; } /// /// Gets or sets whether to use the default grab buttons to grab the object using the grab point. /// public bool UseDefaultGrabButtons { get => _useDefaultGrabButtons; set => _useDefaultGrabButtons = value; } /// /// Gets or sets whether both hands are compatible with the grab point. /// public bool BothHandsCompatible { get => _bothHandsCompatible; set => _bothHandsCompatible = value; } /// /// If is false, tells which hand is used to grab the object using the grab point. /// public UxrHandSide HandSide { get => _handSide; set => _handSide = value; } /// /// If is false, tells which buttons are used to grab the object using the grab /// point. /// public UxrInputButtons InputButtons { get => _inputButtons; set => _inputButtons = value; } /// /// Gets or sets whether to hide the hand while it is grabbing the object using the grab point. /// public bool HideHandGrabberRenderer { get => _hideHandGrabberRenderer; set => _hideHandGrabberRenderer = value; } /// /// Gets or sets the default grip pose info, which is the grip pose info used when an avatar interacts with an object /// and is not registered to have specific properties. /// public UxrGripPoseInfo DefaultGripPoseInfo { get => _defaultGripPoseInfo; set => _defaultGripPoseInfo = value; } /// /// Gets or sets how the object will snap to the hand when it is grabbed using the grab point. /// public UxrSnapToHandMode SnapMode { get => _snapMode; set => _snapMode = value; } /// /// Gets or sets whether the object will snap to the hand or the hand will snap to the object when it is grabbed using /// the grab point. Only used when any kind of snapping is enabled. /// public UxrHandSnapDirection SnapDirection { get => _snapDirection; set => _snapDirection = value; } /// /// Gets or sets which reference to use for snapping when the object is grabbed using the grab point. /// public UxrSnapReference SnapReference { get => _snapReference; set => _snapReference = value; } /// /// Gets or sets whether to align the grab to the controller axes, useful when grabbing objects that require aiming, /// such as weapons. /// public bool AlignToController { get => _alignToController; set => _alignToController = value; } /// /// Gets or sets the transform in the grabbable object to use that will align to the controller axes (x = right, y = /// up, z = forward). /// public Transform AlignToControllerAxes { get => _alignToControllerAxes; set => _alignToControllerAxes = value; } /// /// Gets or sets the proximity mode to use. /// public UxrGrabProximityMode GrabProximityMode { get => _grabProximityMode; set => _grabProximityMode = value; } /// /// Gets or sets the box collider used when is /// . /// public BoxCollider GrabProximityBox { get => _grabProximityBox; set => _grabProximityBox = value; } /// /// Gets or sets the maximum distance the object can be grabbed using this the grab point. /// public float MaxDistanceGrab { get => _maxDistanceGrab; set => _maxDistanceGrab = value; } /// /// Gets or sets whether to use the own transform when computing the distance to /// components. /// public bool GrabProximityTransformUseSelf { get => _grabProximityTransformUseSelf; set => _grabProximityTransformUseSelf = value; } /// /// Gets or sets the that will be used to compute the distance to /// components when is false. /// public Transform GrabProximityTransform { get => _grabProximityTransform; set => _grabProximityTransform = value; } /// /// Gets or sets whether to use the transform when computing the distance to the grab point. /// Otherwise it can specify additional proximity transforms using . /// public bool GrabberProximityUseDefault { get => _grabberProximityUseDefault; set => _grabberProximityUseDefault = value; } /// /// Gets or sets which additional proximity transform from to use when /// is false. /// public int GrabberProximityIndex { get => _grabberProximityIndex; set => _grabberProximityIndex = value; } /// /// Gets or sets the to enable or disable when the object is grabbed or not using the grab /// point. /// public GameObject EnableOnHandNear { get => _enableOnHandNear; set => _enableOnHandNear = value; } #endregion #region Public Methods /// /// Checks whether to create a grip pose entry for the given avatar prefab. /// /// Prefab GUID to generate a grip pose entry for public void CheckAddGripPoseInfo(string avatarGuid) { if (string.IsNullOrEmpty(avatarGuid)) { return; } // Only add if the given avatar prefab isn't found. If any parent prefabs are also registered, the new registered prefab will prevail over the parent prefab entries. if (_avatarGripPoseEntries.All(e => e.AvatarPrefabGuid != avatarGuid)) { _avatarGripPoseEntries.Add(new UxrGripPoseInfo(avatarGuid)); } } /// /// Gets a given grip pose info entry. /// /// Index to retrieve /// Grip pose info. If the index is 0 or not valid, it will return the default grip pose info public UxrGripPoseInfo GetGripPoseInfo(int i) { if (i == 0) { return DefaultGripPoseInfo; } if (i > 0 && i <= _avatarGripPoseEntries.Count) { return _avatarGripPoseEntries[i - 1]; } return null; } /// /// Gets a given grip pose info entry. /// /// Prefab Guid whose info to retrieve /// Grip pose info or null if it wasn't found public UxrGripPoseInfo GetGripPoseInfo(string prefabGuid) { return _avatarGripPoseEntries.FirstOrDefault(i => i.AvatarPrefabGuid == prefabGuid); } /// /// Gets the grip pose info for the given avatar instance or prefab. /// /// Avatar to get the grip pose info for /// /// If the given avatar prefab info wasn't found, whether to look for the pose info for any prefab above the first /// prefab in the hierarchy. This allows child prefabs to inherit poses and manipulation settings of parent prefabs /// /// /// Grip pose info. If is false it will return null if the given prefab wasn't /// found. If is true, it will return if nor the /// prefab nor a parent prefab entry were found /// public UxrGripPoseInfo GetGripPoseInfo(UxrAvatar avatar, bool usePrefabInheritance = true) { foreach (string avatarPrefabGuid in avatar.GetPrefabGuidChain()) { foreach (UxrGripPoseInfo gripPoseInfo in _avatarGripPoseEntries) { if (gripPoseInfo.AvatarPrefabGuid == avatarPrefabGuid) { return gripPoseInfo; } } if (!usePrefabInheritance) { return null; } } return DefaultGripPoseInfo; } /// /// Gets all the grip pose infos that can be used with the given avatar. /// /// The avatar to check /// Whether to check for compatibility using all the parents in the prefab hierarchy /// List of that are potentially compatible with the given avatar public IEnumerable GetCompatibleGripPoseInfos(UxrAvatar avatar, bool usePrefabInheritance = true) { foreach (string avatarPrefabGuid in avatar.GetPrefabGuidChain()) { foreach (UxrGripPoseInfo gripPoseInfo in _avatarGripPoseEntries) { if (gripPoseInfo.AvatarPrefabGuid == avatarPrefabGuid) { yield return gripPoseInfo; } } if (!usePrefabInheritance) { yield break; } } } /// /// Removes the grip pose entry of a given avatar prefab. /// /// Prefab GUID whose information to remove public void RemoveGripPoseInfo(string avatarPrefabGuid) { if (string.IsNullOrEmpty(avatarPrefabGuid)) { return; } _avatarGripPoseEntries.RemoveAll(e => e.AvatarPrefabGuid == avatarPrefabGuid); } #endregion } }