Move third party assets to ThirdParty folder
This commit is contained in:
94
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAlignOnRelease.cs
vendored
Normal file
94
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAlignOnRelease.cs
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAlignOnRelease.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Core.Components;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Aligns an object smoothly whenever it is released to keep it leveled. Should be used on non physics-driven
|
||||
/// grabbable objects, which remain floating in the air when being released.
|
||||
/// </summary>
|
||||
public class UxrAlignOnRelease : UxrComponent
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private bool _onlyLevel = true;
|
||||
[SerializeField] [Range(0.0f, 1.0f)] private float _smoothFactor = 0.2f;
|
||||
[SerializeField] private List<UxrGrabbableObject> _grabbableObjects;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches the transform component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_selfTransform = transform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the transform while the object is not being grabbed.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (!IsBeingGrabbed)
|
||||
{
|
||||
// Smoothly rotate towards horizontal orientation when not being grabbed
|
||||
|
||||
if (_onlyLevel == false)
|
||||
{
|
||||
_selfTransform.rotation = UxrInterpolator.SmoothDampRotation(_selfTransform.rotation, Quaternion.FromToRotation(_selfTransform.up, Vector3.up) * _selfTransform.rotation, _smoothFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 projectedRight = Vector3.ProjectOnPlane(transform.right, Vector3.up);
|
||||
Quaternion targetRotation = Quaternion.FromToRotation(_selfTransform.right, projectedRight) * _selfTransform.rotation;
|
||||
|
||||
if ((targetRotation * Vector3.up).y < 0.0f)
|
||||
{
|
||||
targetRotation = targetRotation * Quaternion.AngleAxis(180.0f, Vector3.forward);
|
||||
}
|
||||
|
||||
_selfTransform.rotation = UxrInterpolator.SmoothDampRotation(_selfTransform.rotation, targetRotation, _smoothFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the object is being grabbed using any of the registered grabbable objects.
|
||||
/// </summary>
|
||||
private bool IsBeingGrabbed
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (UxrGrabbableObject grabbableObject in _grabbableObjects)
|
||||
{
|
||||
if (UxrGrabManager.Instance.IsBeingGrabbed(grabbableObject))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Transform _selfTransform;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAlignOnRelease.cs.meta
vendored
Normal file
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAlignOnRelease.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1dd4099f01318e34680aafb12edd7b4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInAnchor.cs
vendored
Normal file
61
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInAnchor.cs
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAutoSlideInAnchor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.Components;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Anchor component for <see cref="UxrAutoSlideInAnchor" />. Grabbable objects with the
|
||||
/// <see cref="UxrAutoSlideInObject" /> component will automatically attach/detach from this anchor.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(UxrGrabbableObjectAnchor))]
|
||||
public class UxrAutoSlideInAnchor : UxrComponent<UxrAutoSlideInAnchor>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the anchor.
|
||||
/// </summary>
|
||||
public UxrGrabbableObjectAnchor Anchor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_anchor == null)
|
||||
{
|
||||
_anchor = GetComponent<UxrGrabbableObjectAnchor>();
|
||||
}
|
||||
|
||||
return _anchor;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (_anchor == null)
|
||||
{
|
||||
_anchor = GetComponent<UxrGrabbableObjectAnchor>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrGrabbableObjectAnchor _anchor;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInAnchor.cs.meta
vendored
Normal file
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInAnchor.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e85a05d37194014d8a60f3f2f72936a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAutoSlideInObject.StateSave.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.StateSave;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
public partial class UxrAutoSlideInObject
|
||||
{
|
||||
#region Protected Overrides UxrComponent
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SerializeState(bool isReading, int stateSerializationVersion, UxrStateSaveLevel level, UxrStateSaveOptions options)
|
||||
{
|
||||
base.SerializeState(isReading, stateSerializationVersion, level, options);
|
||||
|
||||
// Manipulations are already handled through events, we don't serialize them in incremental changes
|
||||
|
||||
if (level > UxrStateSaveLevel.ChangesSincePreviousSave)
|
||||
{
|
||||
SerializeStateValue(level, options, nameof(_insertAxis), ref _insertAxis);
|
||||
SerializeStateValue(level, options, nameof(_insertOffset), ref _insertOffset);
|
||||
SerializeStateValue(level, options, nameof(_insertOffsetSign), ref _insertOffsetSign);
|
||||
SerializeStateValue(level, options, nameof(_objectLocalSize), ref _objectLocalSize);
|
||||
SerializeStateValue(level, options, nameof(_slideInTimer), ref _slideInTimer);
|
||||
SerializeStateValue(level, options, nameof(_placedAfterSlidingIn), ref _placedAfterSlidingIn);
|
||||
SerializeStateValue(level, options, nameof(_manipulationHapticFeedback), ref _manipulationHapticFeedback);
|
||||
SerializeStateValue(level, options, nameof(_minHapticAmplitude), ref _minHapticAmplitude);
|
||||
SerializeStateValue(level, options, nameof(_maxHapticAmplitude), ref _maxHapticAmplitude);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be3cda6fb2a64942a98f487a1e810b67
|
||||
timeCreated: 1706041007
|
||||
369
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInObject.cs
vendored
Normal file
369
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInObject.cs
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAutoSlideInObject.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UltimateXR.Core.Math;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UltimateXR.Haptics.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that, together with <see cref="UxrAutoSlideInAnchor" /> will add the following behaviour to a
|
||||
/// <see cref="UxrGrabbableObject" />:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// It will slide along the axis given by the grabbable object translation constraint. The constraint should
|
||||
/// be pre-configured along a single axis.
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// It will be smoothly removed from the anchor and made free if dragged beyond the upper translation
|
||||
/// constraint.
|
||||
/// </item>
|
||||
/// <item>It will be smoothly placed automatically on the anchor when moved back close enough.</item>
|
||||
/// <item>It will fall back by itself when released while sliding along the axis.</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public partial class UxrAutoSlideInObject : UxrGrabbableObjectComponent<UxrAutoSlideInObject>
|
||||
{
|
||||
[SerializeField] private Vector3 _translationConstraintMin = Vector3.zero;
|
||||
[SerializeField] private Vector3 _translationConstraintMax = Vector3.forward * 0.1f;
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Event called right after the object hit the end after sliding in after it was released.
|
||||
/// </summary>
|
||||
public event Action PlacedAfterSlidingIn;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the avatars updated event so that the manipulation logic is done after all manipulation
|
||||
/// logic has been updated.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from the avatars updated event.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize component.
|
||||
/// </summary>
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
_placedAfterSlidingIn = GrabbableObject.CurrentAnchor != null;
|
||||
|
||||
// Get slide axis
|
||||
int insertAxis = GrabbableObject.SingleTranslationAxisIndex;
|
||||
|
||||
if (insertAxis == -1 || GrabbableObject.TranslationConstraint != UxrTranslationConstraintMode.RestrictLocalOffset)
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelManipulation >= UxrLogLevel.Errors)
|
||||
{
|
||||
Debug.LogError($"{UxrConstants.ManipulationModule} {this}: {nameof(UxrGrabbableObject)} component needs to have a local offset translation constraint along a single axis to work properly");
|
||||
}
|
||||
|
||||
_insertAxis = UxrAxis.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
_insertAxis = insertAxis;
|
||||
}
|
||||
|
||||
// Store haptic feedback component in case it exists, to disable it while the object is out of the sliding zone
|
||||
_manipulationHapticFeedback = GetComponent<UxrManipulationHapticFeedback>();
|
||||
|
||||
// Compute the slide length
|
||||
_insertOffset = _translationConstraintMax[_insertAxis] > -_translationConstraintMin[_insertAxis] ? _translationConstraintMax[_insertAxis] : _translationConstraintMin[_insertAxis];
|
||||
|
||||
_insertOffsetSign = Mathf.Sign(_insertOffset);
|
||||
_insertOffset = Mathf.Abs(_insertOffset);
|
||||
|
||||
// Fix some object parameters if we need to
|
||||
|
||||
if (GrabbableObject.DropSnapMode != UxrSnapToAnchorMode.DontSnap)
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelManipulation >= UxrLogLevel.Warnings)
|
||||
{
|
||||
Debug.LogWarning($"{UxrConstants.ManipulationModule} {this.GetPathUnderScene()}: GrabbableObject needs DropSnapMode to be DontSnap in order to work properly. Overriding.");
|
||||
}
|
||||
|
||||
GrabbableObject.DropSnapMode = UxrSnapToAnchorMode.DontSnap;
|
||||
}
|
||||
|
||||
GrabbableObject.IsPlaceable = false; // We will handle placement ourselves
|
||||
|
||||
// Compute the object size in local coordinates
|
||||
_objectLocalSize = gameObject.GetLocalBounds(true).size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called after UltimateXR has done all the frame updating. Does the manipulation logic.
|
||||
/// </summary>
|
||||
private void UxrManager_AvatarsUpdated()
|
||||
{
|
||||
bool grabbedByLocalAvatar = UxrGrabManager.Instance.IsBeingGrabbed(GrabbableObject) && UxrGrabManager.Instance.GetGrabbingHands(GrabbableObject).First().Avatar.AvatarMode == UxrAvatarMode.Local;
|
||||
|
||||
if (GrabbableObject.CurrentAnchor == null && grabbedByLocalAvatar)
|
||||
{
|
||||
// The object is being grabbed and is detached. Check if we need to place it on an anchor again by proximity.
|
||||
|
||||
foreach (UxrAutoSlideInAnchor anchor in UxrAutoSlideInAnchor.EnabledComponents.Where(a => a.Anchor.enabled))
|
||||
{
|
||||
// If it is inside the valid release "volume", place it in the anchor again and let it slide by re-assigning the constraints
|
||||
|
||||
if (anchor.Anchor.CurrentPlacedObject == null && anchor.Anchor.IsCompatibleObject(GrabbableObject) && IsObjectNearPlacement(anchor.Anchor))
|
||||
{
|
||||
AttachObject(anchor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GrabbableObject.CurrentAnchor != null && _insertAxis != null)
|
||||
{
|
||||
// Object can only move in a specific axis but if it is grabbed past this distance it becomes free
|
||||
|
||||
if (transform.parent != null && grabbedByLocalAvatar && Mathf.Abs(GrabbableObject.InitialLocalPosition[_insertAxis] - transform.localPosition[_insertAxis]) > _insertOffset * 0.99f)
|
||||
{
|
||||
DetachObject();
|
||||
return;
|
||||
}
|
||||
|
||||
// If it is not being grabbed it will slide in
|
||||
|
||||
if (!GrabbableObject.IsBeingGrabbed)
|
||||
{
|
||||
// Use simple gravity to slide in. Gravity will be mapped to z axis to slide in our local coordinate system.
|
||||
|
||||
Vector3 speed = Physics.gravity * _slideInTimer;
|
||||
Vector3 pos = GrabbableObject.transform.localPosition;
|
||||
pos[_insertAxis] += Time.deltaTime * speed.y * _insertOffsetSign;
|
||||
|
||||
if ((_insertOffsetSign > 0.0f && pos[_insertAxis] < GrabbableObject.InitialLocalPosition[_insertAxis]) ||
|
||||
(_insertOffsetSign < 0.0f && pos[_insertAxis] > GrabbableObject.InitialLocalPosition[_insertAxis]))
|
||||
{
|
||||
pos[_insertAxis] = GrabbableObject.InitialLocalPosition[_insertAxis];
|
||||
|
||||
if (_placedAfterSlidingIn == false)
|
||||
{
|
||||
_placedAfterSlidingIn = true;
|
||||
OnPlacedAfterSlidingIn();
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate other rotation/translation in case the object was released before the transition
|
||||
|
||||
float smooth = 0.1f;
|
||||
|
||||
pos[_insertAxis.Perpendicular] = UxrInterpolator.SmoothDamp(pos[_insertAxis.Perpendicular], GrabbableObject.InitialLocalPosition[_insertAxis.Perpendicular], smooth);
|
||||
pos[_insertAxis.OtherPerpendicular] = UxrInterpolator.SmoothDamp(pos[_insertAxis.OtherPerpendicular], GrabbableObject.InitialLocalPosition[_insertAxis.OtherPerpendicular], smooth);
|
||||
GrabbableObject.transform.localRotation = UxrInterpolator.SmoothDampRotation(GrabbableObject.transform.localRotation, GrabbableObject.InitialLocalRotation, smooth);
|
||||
|
||||
// Update
|
||||
|
||||
GrabbableObject.transform.localPosition = pos;
|
||||
|
||||
_slideInTimer += Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
_slideInTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called when the object was placed at the end sliding in after it was released.
|
||||
/// Use in child classes to
|
||||
/// </summary>
|
||||
protected virtual void OnPlacedAfterSlidingIn()
|
||||
{
|
||||
PlacedAfterSlidingIn?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called right after the object was grabbed.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected override void OnObjectGrabbed(UxrManipulationEventArgs e)
|
||||
{
|
||||
if (!GrabbableObject.IsLockedInPlace)
|
||||
{
|
||||
_placedAfterSlidingIn = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called right after the object was released.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected override void OnObjectReleased(UxrManipulationEventArgs e)
|
||||
{
|
||||
if (e.GrabbableObject.CurrentAnchor != null && e.GrabbableObject.RigidBodySource)
|
||||
{
|
||||
// Force kinematic while released, so that we update the position/rotation.
|
||||
e.GrabbableObject.RigidBodySource.isKinematic = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Overrides UxrGrabbableObjectComponent<UxrAutoSlideInObject>
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsGrabbableObjectRequired => true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Attaches the object to the anchor and assigns constraints to let it slide.
|
||||
/// </summary>
|
||||
protected void AttachObject(UxrAutoSlideInAnchor anchor)
|
||||
{
|
||||
// This method will be synchronized through network
|
||||
BeginSync();
|
||||
|
||||
// Set up constraints and place
|
||||
|
||||
GrabbableObject.TranslationConstraint = UxrTranslationConstraintMode.RestrictLocalOffset;
|
||||
GrabbableObject.RotationConstraint = UxrRotationConstraintMode.Locked;
|
||||
|
||||
GrabbableObject.TranslationLimitsMin = _translationConstraintMin;
|
||||
GrabbableObject.TranslationLimitsMax = _translationConstraintMax;
|
||||
|
||||
UxrGrabManager.Instance.PlaceObject(GrabbableObject, anchor.Anchor, UxrPlacementOptions.Smooth | UxrPlacementOptions.DontRelease, true);
|
||||
|
||||
if (_manipulationHapticFeedback)
|
||||
{
|
||||
_manipulationHapticFeedback.MinAmplitude = _minHapticAmplitude;
|
||||
_manipulationHapticFeedback.MaxAmplitude = _maxHapticAmplitude;
|
||||
}
|
||||
|
||||
EndSyncMethod(new object[] { anchor });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detaches the object from the anchor so that it becomes free.
|
||||
/// </summary>
|
||||
protected void DetachObject()
|
||||
{
|
||||
// This method will be synchronized through network
|
||||
BeginSync();
|
||||
|
||||
if (_manipulationHapticFeedback)
|
||||
{
|
||||
_minHapticAmplitude = _manipulationHapticFeedback.MinAmplitude;
|
||||
_maxHapticAmplitude = _manipulationHapticFeedback.MaxAmplitude;
|
||||
_manipulationHapticFeedback.MinAmplitude = 0.0f;
|
||||
_manipulationHapticFeedback.MaxAmplitude = 0.0f;
|
||||
}
|
||||
|
||||
UxrGrabManager.Instance.RemoveObjectFromAnchor(GrabbableObject, true);
|
||||
GrabbableObject.TranslationConstraint = UxrTranslationConstraintMode.Free;
|
||||
GrabbableObject.RotationConstraint = UxrRotationConstraintMode.Free;
|
||||
|
||||
EndSyncMethod();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the object is close enough to the given anchor to be placed.
|
||||
/// </summary>
|
||||
/// <param name="anchor">Object anchor</param>
|
||||
/// <returns>Whether the object is close enough</returns>
|
||||
private bool IsObjectNearPlacement(UxrGrabbableObjectAnchor anchor)
|
||||
{
|
||||
if (anchor.enabled == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it near enough in the longitudinal axis?
|
||||
|
||||
float threshold = Mathf.Min(0.03f, Mathf.Abs(_insertOffset * 0.1f));
|
||||
|
||||
Vector3 localOffset = anchor.AlignTransform.InverseTransformPoint(GrabbableObject.DropAlignTransform.position) - GrabbableObject.InitialLocalPosition;
|
||||
bool isInLongitudinalAxisRange = (_insertOffsetSign > 0.0f && localOffset[_insertAxis] < +_insertOffset - threshold && localOffset[_insertAxis] > 0.0f) ||
|
||||
(_insertOffsetSign < 0.0f && localOffset[_insertAxis] > -_insertOffset + threshold && localOffset[_insertAxis] < 0.0f);
|
||||
|
||||
// Is it near enough in both other axes?
|
||||
|
||||
float minGrabDistance = float.MaxValue;
|
||||
|
||||
foreach (UxrGrabber grabber in UxrGrabManager.Instance.GetGrabbingHands(GrabbableObject))
|
||||
{
|
||||
UxrGrabPointInfo grabPointInfo = GrabbableObject.GetGrabPoint(UxrGrabManager.Instance.GetGrabbedPoint(grabber));
|
||||
|
||||
if (grabPointInfo.MaxDistanceGrab < minGrabDistance)
|
||||
{
|
||||
minGrabDistance = grabPointInfo.MaxDistanceGrab;
|
||||
}
|
||||
}
|
||||
|
||||
// We use some calculations for the other axes so that it feels good.
|
||||
|
||||
float sizeOneAxis = Mathf.Min(Mathf.Max(_objectLocalSize[_insertAxis.Perpendicular], 0.1f), minGrabDistance);
|
||||
float sizeOtherAxis = Mathf.Min(Mathf.Max(_objectLocalSize[_insertAxis.OtherPerpendicular], 0.1f), minGrabDistance);
|
||||
|
||||
// Return conditions
|
||||
|
||||
return isInLongitudinalAxisRange && Mathf.Abs(localOffset[_insertAxis.Perpendicular]) < sizeOneAxis && Mathf.Abs(localOffset[_insertAxis.OtherPerpendicular]) < sizeOtherAxis;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrAxis _insertAxis;
|
||||
private float _insertOffset;
|
||||
private float _insertOffsetSign;
|
||||
private Vector3 _objectLocalSize;
|
||||
private float _slideInTimer;
|
||||
private bool _placedAfterSlidingIn;
|
||||
private UxrManipulationHapticFeedback _manipulationHapticFeedback;
|
||||
private float _minHapticAmplitude;
|
||||
private float _maxHapticAmplitude;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInObject.cs.meta
vendored
Normal file
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrAutoSlideInObject.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7264c3b787447c4596209ea4b950a39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
100
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrDependentGrabbable.cs
vendored
Normal file
100
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrDependentGrabbable.cs
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrDependentGrabbable.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that allows an object be grabbed only if another object is being grabbed. For instance, it can
|
||||
/// be added to a grenade pin to make sure the pin is never grabbed unless the grenade is being grabbed too.
|
||||
/// Otherwise the pin could be removed by mistake when trying to grab the grenade.
|
||||
/// </summary>
|
||||
public class UxrDependentGrabbable : UxrGrabbableObjectComponent<UxrDependentGrabbable>
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private UxrGrabbableObject _dependentOn;
|
||||
[SerializeField] private bool _onlyOnce;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the grabbable object the component depends on.
|
||||
/// </summary>
|
||||
public UxrGrabbableObject DependentFrom
|
||||
{
|
||||
get => _dependentOn;
|
||||
set => _dependentOn = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to stop toggling the enabled state once the dependent object was grabbed. For instance, a grenade pin
|
||||
/// should remain grabbable once it has been removed from the grenade, no matter if the grenade is being grabbed or
|
||||
/// not at that point.
|
||||
/// </summary>
|
||||
public bool OnlyOnce
|
||||
{
|
||||
get => _onlyOnce;
|
||||
set => _onlyOnce = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the grabbable object state.
|
||||
/// </summary>
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
GrabbableObject.enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the grabbable object state.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (GrabbableObject && DependentFrom && _check)
|
||||
{
|
||||
GrabbableObject.enabled = UxrGrabManager.Instance.IsBeingGrabbed(DependentFrom);
|
||||
|
||||
if (GrabbableObject.enabled && OnlyOnce)
|
||||
{
|
||||
_check = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever the object was grabbed.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected override void OnObjectGrabbed(UxrManipulationEventArgs e)
|
||||
{
|
||||
base.OnObjectGrabbed(e);
|
||||
|
||||
_check = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private bool _check = true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrDependentGrabbable.cs.meta
vendored
Normal file
12
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrDependentGrabbable.cs.meta
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 873afa6bf9451c3479e294d279b19ed9
|
||||
timeCreated: 1492963941
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrGrabbableResizable.StateSave.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.StateSave;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
public sealed partial class UxrGrabbableResizable
|
||||
{
|
||||
#region Protected Overrides UxrComponent
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SerializeState(bool isReading, int stateSerializationVersion, UxrStateSaveLevel level, UxrStateSaveOptions options)
|
||||
{
|
||||
base.SerializeState(isReading, stateSerializationVersion, level, options);
|
||||
|
||||
// Manipulations are already handled through events, we don't serialize them in incremental changes
|
||||
|
||||
if (level > UxrStateSaveLevel.ChangesSincePreviousSave)
|
||||
{
|
||||
SerializeStateValue(level, options, nameof(_grabbingCount), ref _grabbingCount);
|
||||
SerializeStateValue(level, options, nameof(_grabbedCount), ref _grabbedCount);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75671c44324f466baec19cfc69507c7b
|
||||
timeCreated: 1706004361
|
||||
421
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrGrabbableResizable.cs
vendored
Normal file
421
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrGrabbableResizable.cs
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrGrabbableResizable.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Components;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable 67 // Disable warnings due to unused events
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Component that allows an object to be scaled by grabbing it by both sides and moving them closer or apart.
|
||||
/// The hierarchy should be as follows:
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// -Root GameObject: With UxrGrabbableResizable and UxrGrabbableObject component.
|
||||
/// | The UxrGrabbableObject is a dummy grabbable parent that enables moving
|
||||
/// | this root by grabbing the child extensions. It can also have its own
|
||||
/// | grab points but they are not required.
|
||||
/// |---Root resizable: Object that will be scaled when the two extensions are moved.
|
||||
/// |---Grabbable left: Left grabbable extension with locked rotation and translation
|
||||
/// | constrained to sliding it left-right.
|
||||
/// |---Grabbable right: Right grabbable extension with locked rotation and translation
|
||||
/// constrained to sliding it left-right.
|
||||
/// </code>
|
||||
/// All objects should use an axis system with x right, y up and z forward.
|
||||
/// </summary>
|
||||
public sealed partial class UxrGrabbableResizable : UxrComponent, IUxrGrabbable
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[Header("General")] [SerializeField] private Transform _resizableRoot;
|
||||
[SerializeField] private float _startScale = 1.0f;
|
||||
|
||||
[Header("Grabbing")] [SerializeField] private UxrGrabbableObject _grabbableRoot;
|
||||
[SerializeField] private UxrGrabbableObject _grabbableExtendLeft;
|
||||
[SerializeField] private UxrGrabbableObject _grabbableExtendRight;
|
||||
|
||||
[Header("Haptics")] [SerializeField] [Range(0.0f, 1.0f)] private float _hapticsIntensity = 0.1f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Transform" /> that is going to be scaled when the two grabbable objects are moved apart.
|
||||
/// </summary>
|
||||
public Transform ResizableRoot => _resizableRoot;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root grabbable object.
|
||||
/// </summary>
|
||||
public UxrGrabbableObject GrabbableRoot => _grabbableRoot;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left grabbable extension.
|
||||
/// </summary>
|
||||
public UxrGrabbableObject GrabbableExtendLeft => _grabbableExtendLeft;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right grabbable extension.
|
||||
/// </summary>
|
||||
public UxrGrabbableObject GrabbableExtendRight => _grabbableExtendRight;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implicit IUxrGrabbable
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsBeingGrabbed => GrabbableRoot.IsBeingGrabbed || GrabbableExtendLeft.IsBeingGrabbed || GrabbableExtendRight.IsBeingGrabbed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGrabbable
|
||||
{
|
||||
get => GrabbableRoot.IsGrabbable || GrabbableExtendLeft.IsGrabbable || GrabbableExtendRight.IsGrabbable;
|
||||
set
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
GrabbableRoot.IsGrabbable = value;
|
||||
GrabbableExtendLeft.IsGrabbable = value;
|
||||
GrabbableExtendRight.IsGrabbable = value;
|
||||
|
||||
EndSyncProperty(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsKinematic
|
||||
{
|
||||
get => GrabbableRoot.IsKinematic || GrabbableExtendLeft.IsKinematic || GrabbableExtendRight.IsKinematic;
|
||||
set
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
GrabbableRoot.IsKinematic = value;
|
||||
GrabbableExtendLeft.IsKinematic = value;
|
||||
GrabbableExtendRight.IsKinematic = value;
|
||||
|
||||
EndSyncProperty(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Grabbing;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Grabbed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Releasing;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Released;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Placing;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<UxrManipulationEventArgs> Placed;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetPositionAndState(bool propagateEvents)
|
||||
{
|
||||
// This method will be synchronized through network
|
||||
BeginSync();
|
||||
|
||||
ReleaseGrabs(true);
|
||||
GrabbableRoot.ResetPositionAndState(propagateEvents);
|
||||
GrabbableExtendLeft.ResetPositionAndState(propagateEvents);
|
||||
GrabbableExtendRight.ResetPositionAndState(propagateEvents);
|
||||
UpdateResizableScale();
|
||||
|
||||
EndSyncMethod(new object[] { propagateEvents });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReleaseGrabs(bool propagateEvents)
|
||||
{
|
||||
// This method will be synchronized through network
|
||||
BeginSync();
|
||||
|
||||
GrabbableRoot.ReleaseGrabs(propagateEvents);
|
||||
GrabbableExtendLeft.ReleaseGrabs(propagateEvents);
|
||||
GrabbableExtendRight.ReleaseGrabs(propagateEvents);
|
||||
_grabbingCount = 0;
|
||||
_grabbedCount = 0;
|
||||
|
||||
EndSyncMethod(new object[] { propagateEvents });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_initialGrabsSeparation = Vector3.Distance(GrabbableExtendLeft.transform.position, GrabbableExtendRight.transform.position);
|
||||
_initialResizableLocalScale = _resizableRoot.transform.localScale;
|
||||
_separationToBoundsFactor = _initialGrabsSeparation / _resizableRoot.gameObject.GetLocalBounds(true).size.x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to relevant events.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
|
||||
|
||||
GrabbableRoot.Grabbing += Grabbable_Grabbing;
|
||||
GrabbableRoot.Grabbed += Grabbable_Grabbed;
|
||||
GrabbableRoot.Releasing += Grabbable_Releasing;
|
||||
GrabbableRoot.Released += Grabbable_Released;
|
||||
GrabbableExtendLeft.Grabbing += Grabbable_Grabbing;
|
||||
GrabbableExtendLeft.Grabbed += Grabbable_Grabbed;
|
||||
GrabbableExtendLeft.Releasing += Grabbable_Releasing;
|
||||
GrabbableExtendLeft.Released += Grabbable_Released;
|
||||
GrabbableExtendRight.Grabbed += Grabbable_Grabbed;
|
||||
GrabbableExtendRight.Grabbing += Grabbable_Grabbing;
|
||||
GrabbableExtendRight.Releasing += Grabbable_Releasing;
|
||||
GrabbableExtendRight.Released += Grabbable_Released;
|
||||
|
||||
_hapticsCoroutine = StartCoroutine(HapticsCoroutine());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from relevant events.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
|
||||
|
||||
GrabbableRoot.Grabbing -= Grabbable_Grabbing;
|
||||
GrabbableRoot.Grabbed -= Grabbable_Grabbed;
|
||||
GrabbableRoot.Releasing -= Grabbable_Releasing;
|
||||
GrabbableRoot.Released -= Grabbable_Released;
|
||||
GrabbableExtendLeft.Grabbing -= Grabbable_Grabbing;
|
||||
GrabbableExtendLeft.Grabbed -= Grabbable_Grabbed;
|
||||
GrabbableExtendLeft.Releasing -= Grabbable_Releasing;
|
||||
GrabbableExtendLeft.Released -= Grabbable_Released;
|
||||
GrabbableExtendRight.Grabbed -= Grabbable_Grabbed;
|
||||
GrabbableExtendRight.Grabbing -= Grabbable_Grabbing;
|
||||
GrabbableExtendRight.Releasing -= Grabbable_Releasing;
|
||||
GrabbableExtendRight.Released -= Grabbable_Released;
|
||||
|
||||
StopCoroutine(_hapticsCoroutine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the resizable using the initial scale if it's different than 1.0
|
||||
/// </summary>
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
if (!Mathf.Approximately(1.0f, _startScale))
|
||||
{
|
||||
float halfOffset = (_startScale * _initialGrabsSeparation - _initialGrabsSeparation) * 0.5f;
|
||||
GrabbableExtendLeft.transform.localPosition -= Vector3.right * halfOffset;
|
||||
GrabbableExtendRight.transform.localPosition += Vector3.right * halfOffset;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Coroutines
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine that sends haptic feedback in case of scaling.
|
||||
/// </summary>
|
||||
/// <returns>Coroutine IEnumerator</returns>
|
||||
private IEnumerator HapticsCoroutine()
|
||||
{
|
||||
void SendHapticClip(UxrGrabbableObject grabbableObject, UxrHandSide handSide, float speed)
|
||||
{
|
||||
if (_hapticsIntensity < 0.001f || !UxrGrabManager.Instance.GetGrabbingHand(grabbableObject, 0, out UxrGrabber grabber) || grabber.Avatar.AvatarMode != UxrAvatarMode.Local)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float quantityPos = HapticsManipulationMaxSpeed - HapticsManipulationMinSpeed <= 0.0f ? 0.0f : (speed - HapticsManipulationMinSpeed) / (HapticsManipulationMaxSpeed - HapticsManipulationMinSpeed);
|
||||
|
||||
if (quantityPos > 0.0f)
|
||||
{
|
||||
float frequencyPos = Mathf.Lerp(HapticsManipulationMinFrequency, HapticsManipulationMaxFrequency, Mathf.Clamp01(quantityPos));
|
||||
float amplitudePos = Mathf.Lerp(0.1f, 1.0f, Mathf.Clamp01(quantityPos)) * _hapticsIntensity;
|
||||
|
||||
UxrAvatar.LocalAvatarInput.SendHapticFeedback(handSide, frequencyPos, amplitudePos, UxrConstants.InputControllers.HapticSampleDurationSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
float lastDistance = Vector3.Distance(GrabbableExtendLeft.transform.position, GrabbableExtendRight.transform.position);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (_grabbableExtendLeft != null && _grabbableExtendRight != null && _grabbableExtendLeft.IsBeingGrabbed && _grabbableExtendRight.IsBeingGrabbed)
|
||||
{
|
||||
float currentDistance = Vector3.Distance(GrabbableExtendLeft.transform.position, GrabbableExtendRight.transform.position);
|
||||
float speed = Mathf.Abs(lastDistance - currentDistance) / UxrConstants.InputControllers.HapticSampleDurationSeconds;
|
||||
SendHapticClip(_grabbableExtendLeft, UxrHandSide.Left, speed);
|
||||
SendHapticClip(_grabbableExtendRight, UxrHandSide.Right, speed);
|
||||
lastDistance = Vector3.Distance(GrabbableExtendLeft.transform.position, GrabbableExtendRight.transform.position);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(UxrConstants.InputControllers.HapticSampleDurationSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called right after the avatars and manipulation update. Scale the object at this point.
|
||||
/// </summary>
|
||||
private void UxrManager_AvatarsUpdated()
|
||||
{
|
||||
UpdateResizableScale();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when any grabbable is about to be grabbed. It is responsible for sending the appropriate
|
||||
/// <see cref="UxrGrabbableResizable" /> manipulation events if necessary.
|
||||
/// </summary>
|
||||
/// <param name="sender">Event sender</param>
|
||||
/// <param name="e">Event parameters</param>
|
||||
private void Grabbable_Grabbing(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_grabbingCount++;
|
||||
|
||||
if (_grabbingCount == 1)
|
||||
{
|
||||
Grabbing?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called right after any grabbable was grabbed. It is responsible for sending the appropriate
|
||||
/// <see cref="UxrGrabbableResizable" /> manipulation events if necessary.
|
||||
/// </summary>
|
||||
/// <param name="sender">Event sender</param>
|
||||
/// <param name="e">Event parameters</param>
|
||||
private void Grabbable_Grabbed(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_grabbedCount++;
|
||||
|
||||
if (_grabbedCount == 1)
|
||||
{
|
||||
Grabbed?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when any grabbable is about to be released. It is responsible for sending the appropriate
|
||||
/// <see cref="UxrGrabbableResizable" /> manipulation events if necessary.
|
||||
/// </summary>
|
||||
/// <param name="sender">Event sender</param>
|
||||
/// <param name="e">Event parameters</param>
|
||||
private void Grabbable_Releasing(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_grabbingCount--;
|
||||
|
||||
if (_grabbingCount == 0)
|
||||
{
|
||||
Releasing?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called right after any grabbable was released. It is responsible for sending the appropriate
|
||||
/// <see cref="UxrGrabbableResizable" /> manipulation events if necessary.
|
||||
/// </summary>
|
||||
/// <param name="sender">Event sender</param>
|
||||
/// <param name="e">Event parameters</param>
|
||||
private void Grabbable_Released(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_grabbedCount--;
|
||||
|
||||
if (_grabbedCount == 0)
|
||||
{
|
||||
Released?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Updates the resizable scale based on the current separation between the left and right extensions.
|
||||
/// </summary>
|
||||
private void UpdateResizableScale()
|
||||
{
|
||||
float currentGrabSeparation = Vector3.Distance(GrabbableExtendLeft.transform.position, GrabbableExtendRight.transform.position);
|
||||
|
||||
// Move the center in between the two extensions
|
||||
|
||||
Vector3 localCenter = transform.InverseTransformPoint((GrabbableExtendLeft.transform.position + GrabbableExtendRight.transform.position) * 0.5f);
|
||||
|
||||
Vector3 resizableLocalPos = _resizableRoot.transform.localPosition;
|
||||
resizableLocalPos.x = localCenter.x;
|
||||
_resizableRoot.transform.localPosition = resizableLocalPos;
|
||||
|
||||
// Scale the object
|
||||
|
||||
float localScaleZ = _resizableRoot.transform.localScale.z;
|
||||
Vector3 resizableLocalScale = _initialResizableLocalScale * (currentGrabSeparation / _initialGrabsSeparation * _separationToBoundsFactor);
|
||||
resizableLocalScale.z = localScaleZ;
|
||||
_resizableRoot.transform.localScale = resizableLocalScale;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private const float HapticsManipulationMinSpeed = 0.03f;
|
||||
private const float HapticsManipulationMaxSpeed = 1.0f;
|
||||
private const float HapticsManipulationMinFrequency = 10;
|
||||
private const float HapticsManipulationMaxFrequency = 100;
|
||||
|
||||
private Vector3 _initialResizableLocalScale;
|
||||
private float _initialGrabsSeparation;
|
||||
private float _separationToBoundsFactor;
|
||||
private int _grabbingCount;
|
||||
private int _grabbedCount;
|
||||
private Coroutine _hapticsCoroutine;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 67
|
||||
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrGrabbableResizable.cs.meta
vendored
Normal file
11
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrGrabbableResizable.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6293fca64f4b03488a84eb8363cea23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
123
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrRestoreOnRelease.cs
vendored
Normal file
123
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrRestoreOnRelease.cs
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrRestoreOnRelease.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UltimateXR.Core.Math;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that will smoothly restore the original position and orientation of a <see cref="UxrGrabbableObject" />
|
||||
/// when released.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(UxrGrabbableObject))]
|
||||
public class UxrRestoreOnRelease : UxrGrabbableObjectComponent<UxrRestoreOnRelease>
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private UxrEasing _transitionType = UxrEasing.Linear;
|
||||
[SerializeField] private float _transitionSeconds = 0.1f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Updates the transition if it's active.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (_isTransitioning)
|
||||
{
|
||||
_transitionTimer -= Time.deltaTime;
|
||||
|
||||
float t = 1.0f;
|
||||
|
||||
if (_transitionTimer <= 0.0f)
|
||||
{
|
||||
_transitionTimer = 0.0f;
|
||||
_isTransitioning = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = UxrInterpolator.Interpolate(0.0f, 1.0f, 1.0f - _transitionTimer / _transitionSeconds, _transitionType);
|
||||
}
|
||||
|
||||
GrabbableObject.transform.localPosition = Vector3.LerpUnclamped(_initialLocalPosition, GrabbableObject.InitialLocalPosition, t);
|
||||
|
||||
if (_singleRotationAxis != -1 && t >= 0.0f && t <= 1.0f)
|
||||
{
|
||||
// Do not rotate manually here to let UxrGrabbableObject keep track of single axis rotation.
|
||||
// We allow using localRotation outside of the [0, 1] range to support overshooting since otherwise GrabbableObject.SingleRotationAxisDegrees
|
||||
// will clamp the rotation.
|
||||
GrabbableObject.SingleRotationAxisDegrees = Mathf.LerpUnclamped(_initialSingleAxisDegrees, 0.0f, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
GrabbableObject.transform.localRotation = Quaternion.SlerpUnclamped(_initialLocalRotation, GrabbableObject.InitialLocalRotation, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called by the base class whenever the object is grabbed.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains all grab event parameters</param>
|
||||
protected override void OnObjectGrabbed(UxrManipulationEventArgs e)
|
||||
{
|
||||
base.OnObjectGrabbed(e);
|
||||
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_isTransitioning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the base class whenever the object is released.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains all grab event parameters</param>
|
||||
protected override void OnObjectReleased(UxrManipulationEventArgs e)
|
||||
{
|
||||
base.OnObjectReleased(e);
|
||||
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
_isTransitioning = true;
|
||||
_transitionTimer = _transitionSeconds;
|
||||
_initialLocalPosition = e.GrabbableObject.transform.localPosition;
|
||||
_initialLocalRotation = e.GrabbableObject.transform.localRotation;
|
||||
_singleRotationAxis = e.GrabbableObject.SingleRotationAxisIndex;
|
||||
|
||||
if (_singleRotationAxis != -1)
|
||||
{
|
||||
_initialSingleAxisDegrees = e.GrabbableObject.SingleRotationAxisDegrees;
|
||||
}
|
||||
|
||||
// Avoid transitions getting in the way or being executed after the restore ended.
|
||||
e.GrabbableObject.FinishSmoothTransitions();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private bool _isTransitioning;
|
||||
private float _transitionTimer = -1.0f;
|
||||
private Vector3 _initialLocalPosition;
|
||||
private Quaternion _initialLocalRotation;
|
||||
private int _singleRotationAxis;
|
||||
private float _initialSingleAxisDegrees;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
13
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrRestoreOnRelease.cs.meta
vendored
Normal file
13
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrRestoreOnRelease.cs.meta
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a39a5225324a9c44b5248d45300663a
|
||||
timeCreated: 1532426377
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrReturnGrabbableObject.ReturnPolicy.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
public partial class UxrReturnGrabbableObject
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the different policies when returning an object to a previous anchor.
|
||||
/// </summary>
|
||||
public enum ReturnPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Return to last anchor where the object was placed.
|
||||
/// </summary>
|
||||
LastAnchor = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Return to the original anchor where the object was placed.
|
||||
/// </summary>
|
||||
OriginalAnchor,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fe66d825bdb4c3dba0d8252ba3cb221
|
||||
timeCreated: 1693091097
|
||||
157
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrReturnGrabbableObject.cs
vendored
Normal file
157
Assets/ThirdParty/UltimateXR/Runtime/Scripts/Manipulation/Helpers/UxrReturnGrabbableObject.cs
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrReturnGrabbableObject.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Manipulation.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that will always return an <see cref="UxrGrabbableObject" /> to the
|
||||
/// <see cref="UxrGrabbableObjectAnchor" /> it was grabbed from whenever it is released.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(UxrGrabbableObject))]
|
||||
public partial class UxrReturnGrabbableObject : UxrGrabbableObjectComponent<UxrReturnGrabbableObject>
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private bool _smoothTransition = true;
|
||||
[SerializeField] private float _returnDelaySeconds = -1.0f;
|
||||
[SerializeField] private ReturnPolicy _returnPolicy = ReturnPolicy.LastAnchor;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Cancels a return if the given object has a <see cref="UxrReturnGrabbableObject" /> component and a return
|
||||
/// programmed.
|
||||
/// </summary>
|
||||
/// <param name="grabbableObject">Object to try to cancel the return of</param>
|
||||
public static void CancelReturn(UxrGrabbableObject grabbableObject)
|
||||
{
|
||||
if (grabbableObject.gameObject.TryGetComponent<UxrReturnGrabbableObject>(out var returnComponent))
|
||||
{
|
||||
returnComponent.CancelReturn();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Coroutines
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine that returns the object to the original target after some time.
|
||||
/// </summary>
|
||||
/// <param name="grabbableObject">Object to return</param>
|
||||
/// <param name="propagateEvents">Whether to propagate manipulation events</param>
|
||||
/// <returns>Coroutine IEnumerator</returns>
|
||||
private IEnumerator ReturnCoroutine(UxrGrabbableObject grabbableObject, bool propagateEvents)
|
||||
{
|
||||
yield return new WaitForSeconds(_returnDelaySeconds);
|
||||
|
||||
UxrGrabbableObjectAnchor anchor = GetReturnAnchor();
|
||||
|
||||
if (anchor != null && anchor.CurrentPlacedObject == null)
|
||||
{
|
||||
UxrGrabManager.Instance.PlaceObject(grabbableObject, anchor, _smoothTransition ? UxrPlacementOptions.Smooth : UxrPlacementOptions.None, propagateEvents);
|
||||
}
|
||||
|
||||
_returnCoroutine = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called by the base class whenever the object is grabbed.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains all grab event parameters</param>
|
||||
protected override void OnObjectGrabbed(UxrManipulationEventArgs e)
|
||||
{
|
||||
base.OnObjectGrabbed(e);
|
||||
|
||||
if (_returnCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_returnCoroutine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the base class whenever the object is released.
|
||||
/// </summary>
|
||||
/// <param name="e">Contains all grab event parameters</param>
|
||||
protected override void OnObjectReleased(UxrManipulationEventArgs e)
|
||||
{
|
||||
base.OnObjectReleased(e);
|
||||
|
||||
if (e.IsGrabbedStateChanged)
|
||||
{
|
||||
if (e.GrabbableAnchor != null)
|
||||
{
|
||||
_lastObjectAnchor = e.GrabbableAnchor;
|
||||
}
|
||||
|
||||
// Check also dependent grabs. We may be grabbing the object using another grip
|
||||
if (!UxrGrabManager.Instance.IsHandGrabbing(UxrAvatar.LocalAvatar, GrabbableObject, UxrHandSide.Left, true) &&
|
||||
!UxrGrabManager.Instance.IsHandGrabbing(UxrAvatar.LocalAvatar, GrabbableObject, UxrHandSide.Right, true))
|
||||
{
|
||||
if (_returnDelaySeconds <= 0.0f)
|
||||
{
|
||||
// Return to original place
|
||||
UxrGrabManager.Instance.PlaceObject(e.GrabbableObject, GetReturnAnchor(), _smoothTransition ? UxrPlacementOptions.Smooth : UxrPlacementOptions.None, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_returnCoroutine = StartCoroutine(ReturnCoroutine(e.GrabbableObject, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the anchor where the object should be returned.
|
||||
/// </summary>
|
||||
/// <returns>Destination anchor</returns>
|
||||
private UxrGrabbableObjectAnchor GetReturnAnchor()
|
||||
{
|
||||
if (_returnPolicy == ReturnPolicy.LastAnchor && _lastObjectAnchor != null && _lastObjectAnchor.CurrentPlacedObject != null)
|
||||
{
|
||||
return _lastObjectAnchor;
|
||||
}
|
||||
|
||||
return GrabbableObject.StartAnchor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels a return if there was one programmed.
|
||||
/// </summary>
|
||||
private void CancelReturn()
|
||||
{
|
||||
if (_returnCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_returnCoroutine);
|
||||
_returnCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrGrabbableObjectAnchor _lastObjectAnchor;
|
||||
private Coroutine _returnCoroutine;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d08f3c02197a3f4ea71f397b2416ce4
|
||||
timeCreated: 1532426377
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user