Add ultimate xr
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrCatmullRomSpline.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Animation.Splines
|
||||
{
|
||||
/// <summary>
|
||||
/// Catmull-Rom spline. It is used to interpolate smoothly between a set of points.
|
||||
/// </summary>
|
||||
public class UxrCatmullRomSpline : UxrSpline
|
||||
{
|
||||
#region Public Overrides UxrSpline
|
||||
|
||||
/// <summary>
|
||||
/// Does the object contain valid data in order to evaluate the curve?
|
||||
/// </summary>
|
||||
public override bool HasValidData => _points != null && _points.Count > 1;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the curve
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public override bool Evaluate(float t, out Vector3 position)
|
||||
{
|
||||
return Evaluate(t, out position, out float _);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Smoothly interpolates, using Catmull-Rom equations, from p1 to p2 using additional p0 and p3 points.
|
||||
/// </summary>
|
||||
/// <param name="p0">Point 0</param>
|
||||
/// <param name="p1">Point 1</param>
|
||||
/// <param name="p2">Point 2</param>
|
||||
/// <param name="p3">Point 3</param>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <returns>Interpolated point</returns>
|
||||
public static Vector3 Evaluate(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||
{
|
||||
Vector3 ret = new Vector3();
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
ret.x = 0.5f * (2.0f * p1.x + (-p0.x + p2.x) * t + (2.0f * p0.x - 5.0f * p1.x + 4 * p2.x - p3.x) * t2 + (-p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x) * t3);
|
||||
ret.y = 0.5f * (2.0f * p1.y + (-p0.y + p2.y) * t + (2.0f * p0.y - 5.0f * p1.y + 4 * p2.y - p3.y) * t2 + (-p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y) * t3);
|
||||
ret.z = 0.5f * (2.0f * p1.z + (-p0.z + p2.z) * t + (2.0f * p0.z - 5.0f * p1.z + 4 * p2.z - p3.z) * t2 + (-p0.z + 3.0f * p1.z - 3.0f * p2.z + p3.z) * t3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a spline. If <see cref="UxrSpline.UsePrecomputedSampleCount" /> > 0 it will also precompute samples in
|
||||
/// order to evaluate the spline using arc-length parameter.
|
||||
/// </summary>
|
||||
/// <param name="inOutMultiplier">
|
||||
/// Magnitude of spline start and end dummy tangent vectors
|
||||
/// compared to their respective control points. A value of 1 (default) will create dummies
|
||||
/// mirroring p1 and p(n-1) vectors. A different value will multiply these vectors by it.
|
||||
/// It can be used to change the spline start/end curvature.
|
||||
/// </param>
|
||||
/// <param name="points">Set of points defining the curve</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public bool Create(float inOutMultiplier = 1.0f, params Vector3[] points)
|
||||
{
|
||||
_points = new List<Vector3>(points);
|
||||
|
||||
if (points.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_dummyStart = points[0] + (points[0] - points[1]) * inOutMultiplier;
|
||||
_dummyEnd = points[points.Length - 1] + (points[points.Length - 1] - points[points.Length - 2]) * inOutMultiplier;
|
||||
|
||||
ComputeArcLengthSamples();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Interpolates the curve using Catmull-Rom equations.
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated position</param>
|
||||
/// <param name="segmentLength">Length of the segment that this point belongs to</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
private bool Evaluate(float t, out Vector3 position, out float segmentLength)
|
||||
{
|
||||
position = Vector3.zero;
|
||||
segmentLength = 0.0f;
|
||||
|
||||
t = Mathf.Clamp01(t);
|
||||
|
||||
// Compute the index of p1 and build a Catmull segment with 4 points from there
|
||||
int indexA = Mathf.FloorToInt(t * (_points.Count - 1));
|
||||
float segmentT = t * (_points.Count - 1) - indexA;
|
||||
|
||||
if (indexA >= _points.Count - 1)
|
||||
{
|
||||
indexA = _points.Count - 2;
|
||||
segmentT = 1.0f;
|
||||
}
|
||||
|
||||
Vector3 p0 = indexA == 0 ? _dummyStart : _points[indexA - 1];
|
||||
Vector3 p1 = _points[indexA];
|
||||
Vector3 p2 = _points[indexA + 1];
|
||||
Vector3 p3 = indexA >= _points.Count - 2 ? _dummyEnd : _points[indexA + 2];
|
||||
|
||||
segmentLength = Vector3.Distance(p1, p2);
|
||||
|
||||
// Interpolate
|
||||
position = Evaluate(p0, p1, p2, p3, segmentT);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private List<Vector3> _points;
|
||||
private Vector3 _dummyStart;
|
||||
private Vector3 _dummyEnd;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d8fc5a7ef3e485fb34cf8b6e1873e86
|
||||
timeCreated: 1617136491
|
||||
@@ -0,0 +1,103 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrLinearPath.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Animation.Splines
|
||||
{
|
||||
/// <summary>
|
||||
/// Linear interpolation point sequence. It is used to interpolate linearly between a set of points.
|
||||
/// </summary>
|
||||
public class UxrLinearPath : UxrSpline
|
||||
{
|
||||
#region Public Overrides UxrSpline
|
||||
|
||||
/// <summary>
|
||||
/// Does the object contain valid data in order to evaluate the path?
|
||||
/// </summary>
|
||||
public override bool HasValidData => _points != null && _points.Count > 1;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the path.
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public override bool Evaluate(float t, out Vector3 position)
|
||||
{
|
||||
return Evaluate(t, out position, out float _);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creates a path. If <see cref="UxrSpline.UsePrecomputedSampleCount" /> > 0 it will also precompute samples in order
|
||||
/// to evaluate the path using arc-length parameter.
|
||||
/// </summary>
|
||||
/// <param name="points">Set of points defining the curve</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public bool Create(params Vector3[] points)
|
||||
{
|
||||
_points = new List<Vector3>(points);
|
||||
|
||||
if (points.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputeArcLengthSamples();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Interpolates the path using linear interpolation.
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated position</param>
|
||||
/// <param name="segmentLength">Length of the segment that this point belongs to</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
private bool Evaluate(float t, out Vector3 position, out float segmentLength)
|
||||
{
|
||||
position = Vector3.zero;
|
||||
segmentLength = 0.0f;
|
||||
|
||||
t = Mathf.Clamp01(t);
|
||||
|
||||
// Compute the index of p1
|
||||
int indexA = Mathf.FloorToInt(t * (_points.Count - 1));
|
||||
float segmentT = t * (_points.Count - 1) - indexA;
|
||||
|
||||
if (indexA >= _points.Count - 1)
|
||||
{
|
||||
indexA = _points.Count - 2;
|
||||
segmentT = 1.0f;
|
||||
}
|
||||
|
||||
Vector3 p1 = _points[indexA];
|
||||
Vector3 p2 = _points[indexA + 1];
|
||||
|
||||
segmentLength = Vector3.Distance(p1, p2);
|
||||
|
||||
// Interpolate
|
||||
position = Vector3.Lerp(p1, p2, segmentT);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private List<Vector3> _points;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9f35e0f927d2c847b841e54e241cf62
|
||||
timeCreated: 1617136491
|
||||
@@ -0,0 +1,58 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSpline.Sample.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Animation.Splines
|
||||
{
|
||||
public abstract partial class UxrSpline
|
||||
{
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Pre-computed curve sample, used for arc-length parametrization.
|
||||
/// </summary>
|
||||
private class Sample
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the global spline evaluation t value this sample represents.
|
||||
/// </summary>
|
||||
public float LerpT { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the arc-length distance to the start of the spline.
|
||||
/// </summary>
|
||||
public float Distance { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the interpolated spline value.
|
||||
/// </summary>
|
||||
public Vector3 Position { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation value [0.0, 1.0] between the spline start and end position.</param>
|
||||
/// <param name="distance">Arc-length distance to the start</param>
|
||||
/// <param name="position">Spline position</param>
|
||||
public Sample(float t, float distance, Vector3 position)
|
||||
{
|
||||
LerpT = t;
|
||||
Distance = distance;
|
||||
Position = position;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e85cd60e60e41a42a0b644de36927ba
|
||||
timeCreated: 1643733998
|
||||
260
Assets/UltimateXR/Runtime/Scripts/Animation/Splines/UxrSpline.cs
Normal file
260
Assets/UltimateXR/Runtime/Scripts/Animation/Splines/UxrSpline.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSpline.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Animation.Splines
|
||||
{
|
||||
/// <summary>
|
||||
/// Spline base class. We use splines to interpolate smoothly between a set of points.
|
||||
/// Interpolation can be done using the traditional t [0.0f, 1.0f] parameter and also distances to allow
|
||||
/// arc-length evaluation.
|
||||
/// </summary>
|
||||
public abstract partial class UxrSpline
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the spline contains valid data in order to evaluate the curve.
|
||||
/// </summary>
|
||||
public abstract bool HasValidData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actual length of the curve.
|
||||
/// </summary>
|
||||
public float ArcLength => _arcLength;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the spline contains valid data in order to evaluate the curve using arc length parametrization.
|
||||
/// </summary>
|
||||
public bool HasValidArcLengthData => HasValidData && _precomputedSamples != null && _precomputedSamples.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of curve samples that are going to be pre-computed in order to enable arc length parametrization.
|
||||
/// This method must be called before creating the spline and will enable EvaluateUsingArcLength() calls.
|
||||
/// For short splines the default value is enough. For very long splines it may be required to increase the
|
||||
/// sample count.
|
||||
/// </summary>
|
||||
public int UsePrecomputedSampleCount { get; set; } = DefaultPrecomputedSampleCount;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the curve
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public abstract bool Evaluate(float t, out Vector3 position);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the curve
|
||||
/// </summary>
|
||||
/// <param name="t">Interpolation parameter [0.0f, 1.0f]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <param name="direction">Interpolated point direction vector</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public bool Evaluate(float t, out Vector3 position, out Vector3 direction)
|
||||
{
|
||||
position = Vector3.zero;
|
||||
direction = Vector3.zero;
|
||||
|
||||
if (!HasValidData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First the out of range cases. Needed because direction needs distance between the evaluated points.
|
||||
|
||||
// If we have ArcLength information it's helpful to map distance to interpolation value.
|
||||
// Otherwise we risk guessing an interpolation value which may or may not be precise enough.
|
||||
float distanceT = HasValidArcLengthData ? EvalDirectionDistanceArcLength * ArcLength : EvalDirectionDistanceT;
|
||||
|
||||
if (t < 0.0f)
|
||||
{
|
||||
Evaluate(0.0f, out position);
|
||||
Evaluate(distanceT, out Vector3 positionTo);
|
||||
direction = (positionTo - position).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t > 1.0f)
|
||||
{
|
||||
Evaluate(1.0f, out position);
|
||||
Evaluate(1.0f - distanceT, out Vector3 positionFrom);
|
||||
direction = (position - positionFrom).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Evaluate position
|
||||
if (!Evaluate(t, out position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate a position a little bit further, to get the direction (see EvalDirectionDistance constant).
|
||||
if (!Evaluate(t + EvalDirectionDistanceT, out Vector3 position2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute direction vector and normalize
|
||||
direction = (position2 - position).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the curve using arc-length parametrization
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance parameter [0.0f, ArcLength]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public bool EvaluateUsingArcLength(float distance, out Vector3 position)
|
||||
{
|
||||
position = Vector3.zero;
|
||||
|
||||
if (!HasValidArcLengthData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search using the cache
|
||||
int foundPos;
|
||||
|
||||
for (foundPos = _cachedIndexA; foundPos >= 0 && foundPos < _precomputedSamples.Count - 1;)
|
||||
{
|
||||
if (distance < _precomputedSamples[foundPos].Distance)
|
||||
{
|
||||
--foundPos;
|
||||
}
|
||||
else if (distance > _precomputedSamples[foundPos + 1].Distance)
|
||||
{
|
||||
++foundPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foundPos = Mathf.Clamp(foundPos, 0, _precomputedSamples.Count - 2);
|
||||
|
||||
// 0.0f <= segmentT <= 1.0f. It will tell us where in between the two pre-computed points our point lies.
|
||||
float segmentT = (distance - _precomputedSamples[foundPos].Distance)
|
||||
/ (_precomputedSamples[foundPos + 1].Distance - _precomputedSamples[foundPos].Distance);
|
||||
|
||||
// 0.0f <= t <= 1.0f. It will tell us which "t" to use to evaluate our curve.
|
||||
float t = Mathf.Lerp(_precomputedSamples[foundPos].LerpT, _precomputedSamples[foundPos + 1].LerpT, segmentT);
|
||||
|
||||
// Update cache
|
||||
_cachedIndexA = foundPos;
|
||||
_cachedArcLength = _precomputedSamples[foundPos].Distance;
|
||||
|
||||
// Evaluate our curve!
|
||||
return Evaluate(t, out position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the curve using arc-length parametrization
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance parameter [0.0f, ArcLength]</param>
|
||||
/// <param name="position">Interpolated point</param>
|
||||
/// <param name="direction">Interpolated point direction vector</param>
|
||||
/// <returns>Success or failure</returns>
|
||||
public bool EvaluateUsingArcLength(float distance, out Vector3 position, out Vector3 direction)
|
||||
{
|
||||
position = Vector3.zero;
|
||||
direction = Vector3.zero;
|
||||
|
||||
if (!HasValidArcLengthData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early tests. Needed because we need two points with distance between them to compute the direction vector.
|
||||
if (distance <= 0.0f)
|
||||
{
|
||||
Evaluate(0.0f, out position);
|
||||
EvaluateUsingArcLength(EvalDirectionDistanceArcLength, out Vector3 positionTo);
|
||||
direction = (positionTo - position).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (distance >= _arcLength)
|
||||
{
|
||||
Evaluate(1.0f, out position);
|
||||
EvaluateUsingArcLength(1.0f - EvalDirectionDistanceArcLength, out Vector3 positionFrom);
|
||||
direction = (position - positionFrom).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Evaluate position
|
||||
if (!EvaluateUsingArcLength(distance, out position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate a position a little bit further, to get the direction (see EvalDirectionDistance constant)
|
||||
if (!EvaluateUsingArcLength(distance + EvalDirectionDistanceArcLength, out Vector3 position2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute direction vector and normalize
|
||||
direction = (position2 - position).normalized;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Pre-computes a set of samples that will enable to evaluate the curve using arc-length parametrization.
|
||||
/// </summary>
|
||||
protected void ComputeArcLengthSamples()
|
||||
{
|
||||
_precomputedSamples = new List<Sample>();
|
||||
|
||||
_arcLength = 0.0f;
|
||||
Vector3 lastPos = Vector3.zero;
|
||||
|
||||
for (int i = 0; i < UsePrecomputedSampleCount; ++i)
|
||||
{
|
||||
float t = i / (UsePrecomputedSampleCount - 1.0f);
|
||||
Evaluate(t, out Vector3 position);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
_arcLength += Vector3.Distance(lastPos, position);
|
||||
}
|
||||
|
||||
_precomputedSamples.Add(new Sample(t, _arcLength, position));
|
||||
lastPos = position;
|
||||
}
|
||||
|
||||
_cachedIndexA = 0;
|
||||
_cachedArcLength = 0.0f;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private const int DefaultPrecomputedSampleCount = 100;
|
||||
private const float EvalDirectionDistanceT = 0.005f;
|
||||
private const float EvalDirectionDistanceArcLength = 0.005f;
|
||||
|
||||
private float _arcLength;
|
||||
private List<Sample> _precomputedSamples;
|
||||
private int _cachedIndexA;
|
||||
private float _cachedArcLength;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bc7998e9579c344ba0e07282f54a841
|
||||
timeCreated: 1617136491
|
||||
Reference in New Issue
Block a user