using System; using System.Collections.Generic; using UnityEngine; namespace Cinemachine.Utility { internal class PositionPredictor { Vector3 m_Position; const float kSmoothingDefault = 10; float mSmoothing = kSmoothingDefault; public float Smoothing { get { return mSmoothing; } set { if (value != mSmoothing) { mSmoothing = value; int maxRadius = Mathf.Max(10, Mathf.FloorToInt(value * 1.5f)); m_Velocity = new GaussianWindow1D_Vector3(mSmoothing, maxRadius); m_Accel = new GaussianWindow1D_Vector3(mSmoothing, maxRadius); } } } GaussianWindow1D_Vector3 m_Velocity = new GaussianWindow1D_Vector3(kSmoothingDefault); GaussianWindow1D_Vector3 m_Accel = new GaussianWindow1D_Vector3(kSmoothingDefault); public bool IsEmpty { get { return m_Velocity.IsEmpty(); } } public void Reset() { m_Velocity.Reset(); m_Accel.Reset(); } public void AddPosition(Vector3 pos) { if (IsEmpty) m_Velocity.AddValue(Vector3.zero); else { Vector3 vel = m_Velocity.Value(); Vector3 vel2 = (pos - m_Position) / Time.deltaTime; m_Velocity.AddValue(vel2); m_Accel.AddValue(vel2 - vel); } m_Position = pos; } public Vector3 PredictPosition(float lookaheadTime) { int numSteps = Mathf.Min(Mathf.RoundToInt(lookaheadTime / Time.deltaTime), 6); float dt = lookaheadTime / numSteps; Vector3 pos = m_Position; Vector3 vel = m_Velocity.IsEmpty() ? Vector3.zero : m_Velocity.Value(); Vector3 accel = m_Accel.IsEmpty() ? Vector3.zero : m_Accel.Value(); for (int i = 0; i < numSteps; ++i) { pos += vel * dt; Vector3 vel2 = vel + (accel * dt); accel = Quaternion.FromToRotation(vel, vel2) * accel; vel = vel2; } return pos; } } /// Utility to perform realistic damping of float or Vector3 values. /// The algorithm is based on exponentially decaying the delta until only /// a negligible amount remains. public static class Damper { const float Epsilon = UnityVectorExtensions.Epsilon; // Get the decay constant that would leave a given residual after a given time static float DecayConstant(float time, float residual) { return Mathf.Log(1f / residual) / time; } // Exponential decay: decay a given quantity opver a period of time static float Decay(float initial, float decayConstant, float deltaTime) { return initial / Mathf.Exp(decayConstant * deltaTime); } /// Standard residual public const float kNegligibleResidual = 0.01f; /// Get a damped version of a quantity. This is the portion of the /// quantity that will take effect over the given time. /// The amount that will be damped /// The rate of damping. This is the time it would /// take to reduce the original amount to a negligible percentage /// The time over which to damp /// The damped amount. This will be the original amount scaled by /// a value between 0 and 1. public static float Damp(float initial, float dampTime, float deltaTime) { if (dampTime < Epsilon || Mathf.Abs(initial) < Epsilon) return initial; if (deltaTime < Epsilon) return 0; return initial - Decay( initial, DecayConstant(dampTime, kNegligibleResidual), deltaTime); } /// Get a damped version of a quantity. This is the portion of the /// quantity that will take effect over the given time. /// The amount that will be damped /// The rate of damping. This is the time it would /// take to reduce the original amount to a negligible percentage /// The time over which to damp /// The damped amount. This will be the original amount scaled by /// a value between 0 and 1. public static Vector3 Damp(Vector3 initial, Vector3 dampTime, float deltaTime) { for (int i = 0; i < 3; ++i) initial[i] = Damp(initial[i], dampTime[i], deltaTime); return initial; } /// Get a damped version of a quantity. This is the portion of the /// quantity that will take effect over the given time. /// The amount that will be damped /// The rate of damping. This is the time it would /// take to reduce the original amount to a negligible percentage /// The time over which to damp /// The damped amount. This will be the original amount scaled by /// a value between 0 and 1. public static Vector3 Damp(Vector3 initial, float dampTime, float deltaTime) { for (int i = 0; i < 3; ++i) initial[i] = Damp(initial[i], dampTime, deltaTime); return initial; } } }