|
|
- // Velocity Estimator|Utilities|90180
- namespace VRTK
- {
- using UnityEngine;
- using System.Collections;
-
- /// <summary>
- /// The Velocity Estimator is used to calculate an estimated velocity on a moving object that is moving outside of Unity physics.
- /// </summary>
- /// <remarks>
- /// Objects that have rigidbodies and use Unity physics to move around will automatically provide accurate velocity and angular velocity information.
- ///
- /// Any object that is moved around using absolute positions or moving the transform position will not be able to provide accurate velocity or angular velocity information.
- /// When the Velocity Estimator script is applied to any GameObject it will provide a best case estimation of what the object's velocity and angular velocity is based on a given number of position and rotation samples.
- /// The more samples used, the higher the precision but the script will be more demanding on processing time.
- /// </remarks>
- [AddComponentMenu("VRTK/Scripts/Utilities/VRTK_VelocityEstimator")]
- public class VRTK_VelocityEstimator : MonoBehaviour
- {
- [Tooltip("Begin the sampling routine when the script is enabled.")]
- public bool autoStartSampling = true;
- [Tooltip("The number of frames to average when calculating velocity.")]
- public int velocityAverageFrames = 5;
- [Tooltip("The number of frames to average when calculating angular velocity.")]
- public int angularVelocityAverageFrames = 10;
-
- protected Vector3[] velocitySamples;
- protected Vector3[] angularVelocitySamples;
- protected int currentSampleCount;
- protected Coroutine calculateSamplesRoutine;
-
- /// <summary>
- /// The StartEstimation method begins logging samples of position and rotation for the GameObject.
- /// </summary>
- public virtual void StartEstimation()
- {
- EndEstimation();
- calculateSamplesRoutine = StartCoroutine(EstimateVelocity());
- }
-
- /// <summary>
- /// The EndEstimation method stops logging samples of position and rotation for the GameObject.
- /// </summary>
- public virtual void EndEstimation()
- {
- if (calculateSamplesRoutine != null)
- {
- StopCoroutine(calculateSamplesRoutine);
- calculateSamplesRoutine = null;
- }
- }
-
- /// <summary>
- /// The GetVelocityEstimate method returns the current velocity estimate.
- /// </summary>
- /// <returns>The velocity estimate vector of the GameObject</returns>
- public virtual Vector3 GetVelocityEstimate()
- {
- Vector3 velocity = Vector3.zero;
- int velocitySampleCount = Mathf.Min(currentSampleCount, velocitySamples.Length);
- if (velocitySampleCount != 0)
- {
- for (int i = 0; i < velocitySampleCount; i++)
- {
- velocity += velocitySamples[i];
- }
- velocity *= (1.0f / velocitySampleCount);
- }
- return velocity;
- }
-
- /// <summary>
- /// The GetAngularVelocityEstimate method returns the current angular velocity estimate.
- /// </summary>
- /// <returns>The angular velocity estimate vector of the GameObject</returns>
- public virtual Vector3 GetAngularVelocityEstimate()
- {
- Vector3 angularVelocity = Vector3.zero;
- int angularVelocitySampleCount = Mathf.Min(currentSampleCount, angularVelocitySamples.Length);
- if (angularVelocitySampleCount != 0)
- {
- for (int i = 0; i < angularVelocitySampleCount; i++)
- {
- angularVelocity += angularVelocitySamples[i];
- }
- angularVelocity *= (1.0f / angularVelocitySampleCount);
- }
-
- return angularVelocity;
- }
-
- /// <summary>
- /// The GetAccelerationEstimate method returns the current acceleration estimate.
- /// </summary>
- /// <returns>The acceleration estimate vector of the GameObject</returns>
- public virtual Vector3 GetAccelerationEstimate()
- {
- Vector3 average = Vector3.zero;
- for (int i = 2 + currentSampleCount - velocitySamples.Length; i < currentSampleCount; i++)
- {
- if (i < 2)
- {
- continue;
- }
-
- int first = i - 2;
- int second = i - 1;
-
- Vector3 v1 = velocitySamples[first % velocitySamples.Length];
- Vector3 v2 = velocitySamples[second % velocitySamples.Length];
- average += v2 - v1;
- }
- average *= (1.0f / Time.deltaTime);
- return average;
- }
-
- protected virtual void OnEnable()
- {
- InitArrays();
- if (autoStartSampling)
- {
- StartEstimation();
- }
- }
-
- protected virtual void OnDisable()
- {
- EndEstimation();
- }
-
- protected virtual void InitArrays()
- {
- velocitySamples = new Vector3[velocityAverageFrames];
- angularVelocitySamples = new Vector3[angularVelocityAverageFrames];
- }
-
- protected virtual IEnumerator EstimateVelocity()
- {
- currentSampleCount = 0;
-
- Vector3 previousPosition = transform.localPosition;
- Quaternion previousRotation = transform.localRotation;
- while (true)
- {
- yield return new WaitForEndOfFrame();
-
- float velocityFactor = 1.0f / Time.deltaTime;
-
- int v = currentSampleCount % velocitySamples.Length;
- int w = currentSampleCount % angularVelocitySamples.Length;
- currentSampleCount++;
-
- velocitySamples[v] = velocityFactor * (transform.localPosition - previousPosition);
- Quaternion deltaRotation = transform.localRotation * Quaternion.Inverse(previousRotation);
-
- float theta = 2.0f * Mathf.Acos(Mathf.Clamp(deltaRotation.w, -1.0f, 1.0f));
- if (theta > Mathf.PI)
- {
- theta -= 2.0f * Mathf.PI;
- }
-
- Vector3 angularVelocity = new Vector3(deltaRotation.x, deltaRotation.y, deltaRotation.z);
- if (angularVelocity.sqrMagnitude > 0.0f)
- {
- angularVelocity = theta * velocityFactor * angularVelocity.normalized;
- }
-
- angularVelocitySamples[w] = angularVelocity;
-
- previousPosition = transform.localPosition;
- previousRotation = transform.localRotation;
- }
- }
- }
- }
|