#if BURST_PRESENT
using Unity.Burst;
#endif
using System;
using Unity.Mathematics;
using UnityEngine.XR.Interaction.Toolkit.Utilities.Tweenables.Primitives;
namespace UnityEngine.XR.Interaction.Toolkit.Utilities.Tweenables.SmartTweenableVariables
{
///
/// This class expands on the Quaternion tweenable variable to introduce two concepts:
///
/// -
/// A dynamic threshold angle that grows over time in a range,
/// that prevents updating the target so long as the value being assigned to the target is within that threshold.
///
///
/// -
/// A variable speed tween () that inputs a lower and upper range speed for tweening.
/// The closer the value is to the target, the faster the tween.
///
///
///
///
///
#if BURST_PRESENT
[BurstCompile]
#endif
[Obsolete("The Affordance System namespace and all associated classes have been deprecated. The existing affordance system will be moved, replaced and updated with a new interaction feedback system in a future version of XRI.")]
public class SmartFollowQuaternionTweenableVariable : QuaternionTweenableVariable
{
///
/// Minimum angle offset allowed in degrees.
///
public float minAngleAllowed { get; set; }
///
/// Maximum angle offset allowed in degrees.
///
public float maxAngleAllowed { get; set; }
///
/// Time required to elapse before the max angle offset allowed goes from the min angle to the max.
///
public float minToMaxDelaySeconds { get; set; }
float m_LastUpdateTime;
///
/// Constructor for SmartFollowQuaternionTweenableVariable.
///
/// Minimum angle offset (in degrees) from target before which tween starts.
/// Maximum angle offset (in degrees) from target before tween targets, when time threshold is reached.
/// Time required to elapse (in seconds) before the max angle offset allowed goes from the min angle offset to the max.
public SmartFollowQuaternionTweenableVariable(
float minAngleAllowed = 0.1f,
float maxAngleAllowed = 5,
float minToMaxDelaySeconds = 3f)
{
this.minAngleAllowed = minAngleAllowed;
this.maxAngleAllowed = maxAngleAllowed;
this.minToMaxDelaySeconds = minToMaxDelaySeconds;
}
///
/// Checks if the angle difference between the current target rotation and a new target rotation is within a dynamically determined threshold,
/// based on the time since the last update.
///
/// The new target rotation as a Quaternion.
/// Returns if the angle difference between the current and new targets is within the allowed threshold, otherwise.
public bool IsNewTargetWithinThreshold(Quaternion newTarget)
{
float newAngleTargetOffset = Quaternion.Angle(target, newTarget);
float timeSinceLastUpdate = Time.unscaledTime - m_LastUpdateTime;
// Widen tolerance zone over time
float allowedTargetAngleOffset = Mathf.Lerp(minAngleAllowed, maxAngleAllowed, Mathf.Clamp01(timeSinceLastUpdate / minToMaxDelaySeconds));
return newAngleTargetOffset > allowedTargetAngleOffset;
}
///
/// Updates the target rotation to a new value if it is within a dynamically determined threshold,
/// based on the time since the last update.
///
/// The new target rotation as a Quaternion.
/// Returns if the target rotation is updated, otherwise.
public bool SetTargetWithinThreshold(Quaternion newTarget)
{
bool isWithinThreshold = IsNewTargetWithinThreshold(newTarget);
if (isWithinThreshold)
target = newTarget;
return isWithinThreshold;
}
///
protected override void OnTargetChanged(Quaternion newTarget)
{
m_LastUpdateTime = Time.unscaledTime;
}
///
/// Tween to new target with variable speed according to distance from target.
/// The closer the target is to the current value, the faster the tween.
///
/// Time elapsed since last tween.
/// Lower speed limit new tween target will clamp to.
/// Upper speed limit new tween target will clamp to.
public void HandleSmartTween(float deltaTime, float lowerSpeed, float upperSpeed)
{
float angleOffsetDeg = Quaternion.Angle(target, Value);
ComputeNewTweenTarget(deltaTime, angleOffsetDeg, maxAngleAllowed, lowerSpeed, upperSpeed, out float newTweenTarget);
HandleTween(newTweenTarget);
}
#if BURST_PRESENT
[BurstCompile]
#endif
static void ComputeNewTweenTarget(float deltaTime, float angleOffsetDeg, float maxAngleAllowed, float lowerSpeed, float upperSpeed, out float newTweenTarget)
{
float speedMultiplier = (1f - math.clamp(angleOffsetDeg / maxAngleAllowed, 0f, 1f));
newTweenTarget = deltaTime * math.clamp(speedMultiplier * upperSpeed, lowerSpeed, upperSpeed);
}
}
}