Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.7 KiB

  1. // Velocity Estimator|Utilities|90180
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. using System.Collections;
  6. /// <summary>
  7. /// The Velocity Estimator is used to calculate an estimated velocity on a moving object that is moving outside of Unity physics.
  8. /// </summary>
  9. /// <remarks>
  10. /// Objects that have rigidbodies and use Unity physics to move around will automatically provide accurate velocity and angular velocity information.
  11. ///
  12. /// 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.
  13. /// 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.
  14. /// The more samples used, the higher the precision but the script will be more demanding on processing time.
  15. /// </remarks>
  16. [AddComponentMenu("VRTK/Scripts/Utilities/VRTK_VelocityEstimator")]
  17. public class VRTK_VelocityEstimator : MonoBehaviour
  18. {
  19. [Tooltip("Begin the sampling routine when the script is enabled.")]
  20. public bool autoStartSampling = true;
  21. [Tooltip("The number of frames to average when calculating velocity.")]
  22. public int velocityAverageFrames = 5;
  23. [Tooltip("The number of frames to average when calculating angular velocity.")]
  24. public int angularVelocityAverageFrames = 10;
  25. protected Vector3[] velocitySamples;
  26. protected Vector3[] angularVelocitySamples;
  27. protected int currentSampleCount;
  28. protected Coroutine calculateSamplesRoutine;
  29. /// <summary>
  30. /// The StartEstimation method begins logging samples of position and rotation for the GameObject.
  31. /// </summary>
  32. public virtual void StartEstimation()
  33. {
  34. EndEstimation();
  35. calculateSamplesRoutine = StartCoroutine(EstimateVelocity());
  36. }
  37. /// <summary>
  38. /// The EndEstimation method stops logging samples of position and rotation for the GameObject.
  39. /// </summary>
  40. public virtual void EndEstimation()
  41. {
  42. if (calculateSamplesRoutine != null)
  43. {
  44. StopCoroutine(calculateSamplesRoutine);
  45. calculateSamplesRoutine = null;
  46. }
  47. }
  48. /// <summary>
  49. /// The GetVelocityEstimate method returns the current velocity estimate.
  50. /// </summary>
  51. /// <returns>The velocity estimate vector of the GameObject</returns>
  52. public virtual Vector3 GetVelocityEstimate()
  53. {
  54. Vector3 velocity = Vector3.zero;
  55. int velocitySampleCount = Mathf.Min(currentSampleCount, velocitySamples.Length);
  56. if (velocitySampleCount != 0)
  57. {
  58. for (int i = 0; i < velocitySampleCount; i++)
  59. {
  60. velocity += velocitySamples[i];
  61. }
  62. velocity *= (1.0f / velocitySampleCount);
  63. }
  64. return velocity;
  65. }
  66. /// <summary>
  67. /// The GetAngularVelocityEstimate method returns the current angular velocity estimate.
  68. /// </summary>
  69. /// <returns>The angular velocity estimate vector of the GameObject</returns>
  70. public virtual Vector3 GetAngularVelocityEstimate()
  71. {
  72. Vector3 angularVelocity = Vector3.zero;
  73. int angularVelocitySampleCount = Mathf.Min(currentSampleCount, angularVelocitySamples.Length);
  74. if (angularVelocitySampleCount != 0)
  75. {
  76. for (int i = 0; i < angularVelocitySampleCount; i++)
  77. {
  78. angularVelocity += angularVelocitySamples[i];
  79. }
  80. angularVelocity *= (1.0f / angularVelocitySampleCount);
  81. }
  82. return angularVelocity;
  83. }
  84. /// <summary>
  85. /// The GetAccelerationEstimate method returns the current acceleration estimate.
  86. /// </summary>
  87. /// <returns>The acceleration estimate vector of the GameObject</returns>
  88. public virtual Vector3 GetAccelerationEstimate()
  89. {
  90. Vector3 average = Vector3.zero;
  91. for (int i = 2 + currentSampleCount - velocitySamples.Length; i < currentSampleCount; i++)
  92. {
  93. if (i < 2)
  94. {
  95. continue;
  96. }
  97. int first = i - 2;
  98. int second = i - 1;
  99. Vector3 v1 = velocitySamples[first % velocitySamples.Length];
  100. Vector3 v2 = velocitySamples[second % velocitySamples.Length];
  101. average += v2 - v1;
  102. }
  103. average *= (1.0f / Time.deltaTime);
  104. return average;
  105. }
  106. protected virtual void OnEnable()
  107. {
  108. InitArrays();
  109. if (autoStartSampling)
  110. {
  111. StartEstimation();
  112. }
  113. }
  114. protected virtual void OnDisable()
  115. {
  116. EndEstimation();
  117. }
  118. protected virtual void InitArrays()
  119. {
  120. velocitySamples = new Vector3[velocityAverageFrames];
  121. angularVelocitySamples = new Vector3[angularVelocityAverageFrames];
  122. }
  123. protected virtual IEnumerator EstimateVelocity()
  124. {
  125. currentSampleCount = 0;
  126. Vector3 previousPosition = transform.localPosition;
  127. Quaternion previousRotation = transform.localRotation;
  128. while (true)
  129. {
  130. yield return new WaitForEndOfFrame();
  131. float velocityFactor = 1.0f / Time.deltaTime;
  132. int v = currentSampleCount % velocitySamples.Length;
  133. int w = currentSampleCount % angularVelocitySamples.Length;
  134. currentSampleCount++;
  135. velocitySamples[v] = velocityFactor * (transform.localPosition - previousPosition);
  136. Quaternion deltaRotation = transform.localRotation * Quaternion.Inverse(previousRotation);
  137. float theta = 2.0f * Mathf.Acos(Mathf.Clamp(deltaRotation.w, -1.0f, 1.0f));
  138. if (theta > Mathf.PI)
  139. {
  140. theta -= 2.0f * Mathf.PI;
  141. }
  142. Vector3 angularVelocity = new Vector3(deltaRotation.x, deltaRotation.y, deltaRotation.z);
  143. if (angularVelocity.sqrMagnitude > 0.0f)
  144. {
  145. angularVelocity = theta * velocityFactor * angularVelocity.normalized;
  146. }
  147. angularVelocitySamples[w] = angularVelocity;
  148. previousPosition = transform.localPosition;
  149. previousRotation = transform.localRotation;
  150. }
  151. }
  152. }
  153. }