IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
VelocityEstimator.cs
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 
7 using UnityEngine;
8 using System.Collections;
9 
10 namespace Valve.VR.InteractionSystem
11 {
12  //-------------------------------------------------------------------------
13  public class VelocityEstimator : MonoBehaviour
14  {
15  [Tooltip( "How many frames to average over for computing velocity" )]
16  public int velocityAverageFrames = 5;
17  [Tooltip( "How many frames to average over for computing angular velocity" )]
18  public int angularVelocityAverageFrames = 11;
19 
20  public bool estimateOnAwake = false;
21 
22  private Coroutine routine;
23  private int sampleCount;
24  private Vector3[] velocitySamples;
25  private Vector3[] angularVelocitySamples;
26 
27 
28  //-------------------------------------------------
29  public void BeginEstimatingVelocity()
30  {
31  FinishEstimatingVelocity();
32 
33  routine = StartCoroutine( EstimateVelocityCoroutine() );
34  }
35 
36 
37  //-------------------------------------------------
38  public void FinishEstimatingVelocity()
39  {
40  if ( routine != null )
41  {
42  StopCoroutine( routine );
43  routine = null;
44  }
45  }
46 
47 
48  //-------------------------------------------------
49  public Vector3 GetVelocityEstimate()
50  {
51  // Compute average velocity
52  Vector3 velocity = Vector3.zero;
53  int velocitySampleCount = Mathf.Min( sampleCount, velocitySamples.Length );
54  if ( velocitySampleCount != 0 )
55  {
56  for ( int i = 0; i < velocitySampleCount; i++ )
57  {
58  velocity += velocitySamples[i];
59  }
60  velocity *= ( 1.0f / velocitySampleCount );
61  }
62 
63  return velocity;
64  }
65 
66 
67  //-------------------------------------------------
68  public Vector3 GetAngularVelocityEstimate()
69  {
70  // Compute average angular velocity
71  Vector3 angularVelocity = Vector3.zero;
72  int angularVelocitySampleCount = Mathf.Min( sampleCount, angularVelocitySamples.Length );
73  if ( angularVelocitySampleCount != 0 )
74  {
75  for ( int i = 0; i < angularVelocitySampleCount; i++ )
76  {
77  angularVelocity += angularVelocitySamples[i];
78  }
79  angularVelocity *= ( 1.0f / angularVelocitySampleCount );
80  }
81 
82  return angularVelocity;
83  }
84 
85 
86  //-------------------------------------------------
87  public Vector3 GetAccelerationEstimate()
88  {
89  Vector3 average = Vector3.zero;
90  for ( int i = 2 + sampleCount - velocitySamples.Length; i < sampleCount; i++ )
91  {
92  if ( i < 2 )
93  continue;
94 
95  int first = i - 2;
96  int second = i - 1;
97 
98  Vector3 v1 = velocitySamples[first % velocitySamples.Length];
99  Vector3 v2 = velocitySamples[second % velocitySamples.Length];
100  average += v2 - v1;
101  }
102  average *= ( 1.0f / Time.deltaTime );
103  return average;
104  }
105 
106 
107  //-------------------------------------------------
108  void Awake()
109  {
110  velocitySamples = new Vector3[velocityAverageFrames];
111  angularVelocitySamples = new Vector3[angularVelocityAverageFrames];
112 
113  if ( estimateOnAwake )
114  {
115  BeginEstimatingVelocity();
116  }
117  }
118 
119 
120  //-------------------------------------------------
121  private IEnumerator EstimateVelocityCoroutine()
122  {
123  sampleCount = 0;
124 
125  Vector3 previousPosition = transform.position;
126  Quaternion previousRotation = transform.rotation;
127  while ( true )
128  {
129  yield return new WaitForEndOfFrame();
130 
131  float velocityFactor = 1.0f / Time.deltaTime;
132 
133  int v = sampleCount % velocitySamples.Length;
134  int w = sampleCount % angularVelocitySamples.Length;
135  sampleCount++;
136 
137  // Estimate linear velocity
138  velocitySamples[v] = velocityFactor * ( transform.position - previousPosition );
139 
140  // Estimate angular velocity
141  Quaternion deltaRotation = transform.rotation * Quaternion.Inverse( previousRotation );
142 
143  float theta = 2.0f * Mathf.Acos( Mathf.Clamp( deltaRotation.w, -1.0f, 1.0f ) );
144  if ( theta > Mathf.PI )
145  {
146  theta -= 2.0f * Mathf.PI;
147  }
148 
149  Vector3 angularVelocity = new Vector3( deltaRotation.x, deltaRotation.y, deltaRotation.z );
150  if ( angularVelocity.sqrMagnitude > 0.0f )
151  {
152  angularVelocity = theta * velocityFactor * angularVelocity.normalized;
153  }
154 
155  angularVelocitySamples[w] = angularVelocity;
156 
157  previousPosition = transform.position;
158  previousRotation = transform.rotation;
159  }
160  }
161  }
162 }