VelocityEstimator.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Estimates the velocity of an object based on change in position
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using System.Collections;
  8. namespace Rokid.UXR.Interaction
  9. {
  10. //-------------------------------------------------------------------------
  11. public class VelocityEstimator : MonoBehaviour
  12. {
  13. [Tooltip("How many frames to average over for computing velocity")]
  14. public int velocityAverageFrames = 5;
  15. [Tooltip("How many frames to average over for computing angular velocity")]
  16. public int angularVelocityAverageFrames = 11;
  17. public bool estimateOnAwake = false;
  18. private Coroutine routine;
  19. private int sampleCount;
  20. [SerializeField]
  21. private Vector3[] velocitySamples;
  22. [SerializeField]
  23. private Vector3[] angularVelocitySamples;
  24. private WaitForSeconds waitForSeconds = new WaitForSeconds(0.03f);
  25. private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
  26. //-------------------------------------------------
  27. public void BeginEstimatingVelocity()
  28. {
  29. FinishEstimatingVelocity();
  30. routine = StartCoroutine(EstimateVelocityCoroutine());
  31. }
  32. //-------------------------------------------------
  33. public void FinishEstimatingVelocity()
  34. {
  35. if (routine != null)
  36. {
  37. StopCoroutine(routine);
  38. routine = null;
  39. }
  40. }
  41. //-------------------------------------------------
  42. public Vector3 GetVelocityEstimate()
  43. {
  44. // Compute average velocity
  45. Vector3 velocity = Vector3.zero;
  46. int velocitySampleCount = Mathf.Min(sampleCount, velocitySamples.Length);
  47. if (velocitySampleCount != 0)
  48. {
  49. for (int i = 0; i < velocitySampleCount; i++)
  50. {
  51. velocity += velocitySamples[i];
  52. }
  53. velocity *= (1.0f / velocitySampleCount);
  54. }
  55. return velocity;
  56. }
  57. //-------------------------------------------------
  58. public Vector3 GetAngularVelocityEstimate()
  59. {
  60. // Compute average angular velocity
  61. Vector3 angularVelocity = Vector3.zero;
  62. int angularVelocitySampleCount = Mathf.Min(sampleCount, angularVelocitySamples.Length);
  63. if (angularVelocitySampleCount != 0)
  64. {
  65. for (int i = 0; i < angularVelocitySampleCount; i++)
  66. {
  67. angularVelocity += angularVelocitySamples[i];
  68. }
  69. angularVelocity *= (1.0f / angularVelocitySampleCount);
  70. }
  71. return angularVelocity;
  72. }
  73. //-------------------------------------------------
  74. public Vector3 GetAccelerationEstimate()
  75. {
  76. Vector3 average = Vector3.zero;
  77. for (int i = 2 + sampleCount - velocitySamples.Length; i < sampleCount; i++)
  78. {
  79. if (i < 2)
  80. continue;
  81. int first = i - 2;
  82. int second = i - 1;
  83. Vector3 v1 = velocitySamples[first % velocitySamples.Length];
  84. Vector3 v2 = velocitySamples[second % velocitySamples.Length];
  85. average += v2 - v1;
  86. }
  87. average *= (1.0f / Time.deltaTime);
  88. return average;
  89. }
  90. //-------------------------------------------------
  91. void Awake()
  92. {
  93. velocitySamples = new Vector3[velocityAverageFrames];
  94. angularVelocitySamples = new Vector3[angularVelocityAverageFrames];
  95. if (estimateOnAwake)
  96. {
  97. BeginEstimatingVelocity();
  98. }
  99. }
  100. //-------------------------------------------------
  101. private IEnumerator EstimateVelocityCoroutine()
  102. {
  103. sampleCount = 0;
  104. Vector3 previousPosition = transform.position;
  105. Quaternion previousRotation = transform.rotation;
  106. while (true)
  107. {
  108. yield return waitForEndOfFrame;
  109. float velocityFactor = 1.0f / Time.deltaTime;
  110. int v = sampleCount % velocitySamples.Length;
  111. int w = sampleCount % angularVelocitySamples.Length;
  112. //RKLog.Info($"v,w+{v},{w}");
  113. sampleCount++;
  114. // Estimate linear velocity
  115. velocitySamples[v] = velocityFactor * (transform.position - previousPosition);
  116. // Estimate angular velocity
  117. Quaternion deltaRotation = transform.rotation * Quaternion.Inverse(previousRotation);
  118. float theta = 2.0f * Mathf.Acos(Mathf.Clamp(deltaRotation.w, -1.0f, 1.0f));
  119. if (theta > Mathf.PI)
  120. {
  121. theta -= 2.0f * Mathf.PI;
  122. }
  123. Vector3 angularVelocity = new Vector3(deltaRotation.x, deltaRotation.y, deltaRotation.z);
  124. if (angularVelocity.sqrMagnitude > 0.0f)
  125. {
  126. angularVelocity = theta * velocityFactor * angularVelocity.normalized;
  127. }
  128. angularVelocitySamples[w] = angularVelocity;
  129. previousPosition = transform.position;
  130. previousRotation = transform.rotation;
  131. }
  132. }
  133. }
  134. }