AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
GestureInteractiveControl.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using UnityEngine;
5 using System.Collections;
6 using HoloToolkit.Unity;
7 
8 namespace HoloToolkit.Examples.InteractiveElements
9 {
27  public struct GestureInteractiveData
28  {
29  public Vector3 AlignmentVector;
30  public Vector3 Direction;
31  public float Distance;
32  public float Percentage;
33  public float MaxDistance;
35 
36  public GestureInteractiveData(Vector3 alignmentVector, float maxDistance, bool flipDirectionOnCameraForward)
37  {
38  AlignmentVector = alignmentVector;
39  MaxDistance = maxDistance;
40  FlipDirecationOnCameraForward = flipDirectionOnCameraForward;
41  Direction = new Vector3();
42  Distance = 0;
43  Percentage = 0;
44  }
45  }
46 
47  public class GestureInteractiveControl : MonoBehaviour
48  {
55  public enum GestureDataType { Raw, Camera, Aligned }
56 
57  [Tooltip("What type of data processing should be used ? Raw, Camera aligned or vector aligned")]
59 
64  [Tooltip("The distance in world space to compare the gesture's delta to")]
65  public float MaxGestureDistance = 0.15f;
66 
71  [Tooltip("The vector to align the gesture to, only used when the Aligned GestureDataType is selected.")]
72  public Vector3 AlignmentVector = new Vector3(1,1,1);
73 
79  [Tooltip("Should we care if the Camera's forward is not Vector3.forward?")]
80  public bool FlipDirectionOnCameraForward = false;
81 
86 
90  protected Camera MainCamera { get { return CameraCache.Main; } }
91 
96  protected Matrix4x4 CameraMatrix;
97 
101  protected Vector3 StartGesturePosition;
102 
106  protected Vector3 CurrentGesturePosition;
107 
111  protected Vector3 DirectionVector;
112 
116  protected Vector3 StartHeadPosition;
117 
121  protected Vector3 StartHeadRay;
122 
126  protected bool GestureStarted = false;
127 
133  protected float CurrentDistance;
134 
138  protected float CurrentPercentage;
139 
143  protected float KeywordGestureTime = 0.5f;
144 
148  protected float KeywordGestureTimeCounter = 0.5f;
149 
153  protected Vector3 KeywordGestureVector;
154 
155  // set the default gesture state
156  virtual protected void Awake()
157  {
158  GestureState = GestureInteractive.GestureManipulationState.None;
159 
160  }
161 
170  public virtual void ManipulationUpdate(Vector3 startGesturePosition, Vector3 currentGesturePosition, Vector3 startHeadOrigin, Vector3 startHeadRay, GestureInteractive.GestureManipulationState gestureState)
171  {
172  if (gestureState == GestureInteractive.GestureManipulationState.Start || (!GestureStarted && gestureState != GestureInteractive.GestureManipulationState.Start))
173  {
174  CameraMatrix = GetCameraMatrix();
175  StartGesturePosition = startGesturePosition;
176  CurrentGesturePosition = startGesturePosition;
177  StartHeadPosition = startHeadOrigin;
178  StartHeadRay = startHeadRay;
179  GestureStarted = true;
180  }
181  else
182  {
183  CurrentGesturePosition = currentGesturePosition;
184  }
185 
186  UpdateGesture();
187 
188  if (gestureState == GestureInteractive.GestureManipulationState.None)
189  {
190  GestureStarted = false;
191  }
192  }
193 
204  public GestureInteractiveData GetGestureData(Vector3 alignmentVector, float maxDistance, bool flipDirecationOnCameraForward)
205  {
206  GestureInteractiveData data = new GestureInteractiveData(alignmentVector, maxDistance, flipDirecationOnCameraForward);
207 
208  data.Direction = DirectionVector;
209  bool flipDirection = Vector3.Dot(Vector3.forward, StartHeadRay) < 0 && flipDirecationOnCameraForward;
210 
211  if (flipDirection)
212  {
213  data.Direction = -data.Direction;
214  }
215  data.Distance = Vector3.Dot(data.Direction, alignmentVector);
216 
217  data.Percentage = Mathf.Min(Mathf.Abs(data.Distance) / maxDistance, 1);
218 
219  return data;
220  }
221 
226  public Matrix4x4 GetCameraMatrix()
227  {
228  // get the preferred body direction
229  Vector3 up = Vector3.up;
230  Vector3 forward = MainCamera.transform.forward;
231  // protecting from a weird cross value
232  if (Vector3.Angle(up, forward) < 10)
233  {
234  up = MainCamera.transform.up;
235  }
236  Vector3 right = Vector3.Cross(up, forward);
237  right.Normalize();
238 
239  // build a matrix based on body/camera direction
240  Matrix4x4 cameraWorld = new Matrix4x4();
241  cameraWorld.SetColumn(0, right);
242  cameraWorld.SetColumn(1, up);
243  cameraWorld.SetColumn(2, forward);
244  cameraWorld.SetColumn(3, new Vector4(0, 0, 0, 1));
245 
246  return cameraWorld;
247  }
248 
255  public Vector3 WorldForwardVector(Vector3 direction, Vector3 orientation, bool flipY = false, bool flipZ = false)
256  {
257  Matrix4x4 cameraWorld = GetCameraMatrix(); //CameraMatrix
258 
259  // create a new vector from the raw gesture data
260  Vector3 rawVector = direction - orientation;
261 
262  // flip z index?
263  if (flipZ)
264  {
265  rawVector.z = -rawVector.z;
266  }
267 
268  if (flipY)
269  {
270  rawVector.y = -rawVector.y;
271  }
272 
273  Vector3 newDirection = cameraWorld.MultiplyVector(rawVector);
274 
275  // replace the y
276  newDirection.y = rawVector.y;
277 
278  return newDirection;
279  }
280 
285  public void SetGestureVector(Vector3 gestureVector)
286  {
287  if (GestureStarted)
288  {
289  return;
290  }
291 
292  KeywordGestureVector = gestureVector;
293  KeywordGestureTimeCounter = 0;
294  CameraMatrix = GetCameraMatrix();
295  StartGesturePosition = gestureVector * MaxGestureDistance * (KeywordGestureTimeCounter / KeywordGestureTime);
296  StartHeadPosition = new Vector3();
297  StartHeadRay = Vector3.forward;
298 
299  CurrentGesturePosition = gestureVector * MaxGestureDistance * (KeywordGestureTimeCounter/KeywordGestureTime);
300 
301  ManipulationUpdate(StartGesturePosition, Vector3.up, StartHeadPosition, StartHeadRay, GestureInteractive.GestureManipulationState.Start);
302  }
303 
310  public virtual void setGestureValue(int gestureValue)
311  {
312  // override to convert keyword index to vectors.
313  switch (gestureValue)
314  {
315  case 0:
316  SetGestureVector(Vector3.left);
317  break;
318  case 1:
319  SetGestureVector(Vector3.right);
320  break;
321  case 2:
322  SetGestureVector(Vector3.up);
323  break;
324  case 3:
325  SetGestureVector(Vector3.down);
326  break;
327  }
328  }
329 
337  protected Vector3 DirectionVectorToZPlane(Vector3 directionVector, bool flipX, bool flipY)
338  {
339  // set the direction based on camera and gesture updates
340  float cameraDirectionX = flipX ? -directionVector.x : directionVector.x;
341  float cameraDirectionY = flipY ? -directionVector.y : directionVector.y;
342  return MainCamera.transform.forward * cameraDirectionY + MainCamera.transform.right * cameraDirectionX;
343  }
344 
351  public Vector3 GesturePosition(Vector3 gesturePosition)
352  {
353  // rotate the screen space mouse position to world space, based on the camera direction and compress pixels to world
354  // get current angle from forward - returns an absolute value of 0 - 180
355  float angleDiff = Vector3.Angle(Vector3.forward, MainCamera.transform.forward);
356  // make sure angle works 360 degrees, find the left or right side
357  float dot = Vector3.Dot(Vector3.right, MainCamera.transform.forward);
358  // if dot is positive, camera is pointing right of Vector3.forward or rotating clockwise
359  if (dot < 0)
360  angleDiff = -angleDiff;
361  // rotate the world space converted mouse vector on the Y axis
362  return RotateVectorOnY(gesturePosition, MainCamera.transform.position, angleDiff);
363  }
364 
372  private Vector3 RotateVectorOnY(Vector3 vector, Vector3 pivot, float angle)
373  {
374  return Quaternion.Euler(0, angle, 0) * (vector - pivot) + pivot;
375  }
376 
386  protected float FlipDistanceOnFacingControl(float toFlip, Vector3 controlPosition, Vector3 controlForward)
387  {
388  Vector3 cameraRay = StartHeadPosition - controlPosition;
389  bool facingForward = Vector3.Dot(MainCamera.transform.forward, StartHeadRay) >= 0;
390  bool facingControl = Vector3.Dot(cameraRay, controlForward) >= 0;
391 
392  if (!facingForward)
393  {
394  // then the direction was flipped
395  // facing back
396  if (facingControl)
397  {
398  toFlip = -toFlip;
399  }
400  }
401  else
402  {
403  if (!facingControl)
404  {
405  toFlip = -toFlip;
406  }
407  }
408 
409  return toFlip;
410  }
411 
416  protected void UpdateGesture()
417  {
418  DirectionVector = CurrentGesturePosition - StartGesturePosition;
419  CurrentDistance = DirectionVector.magnitude;
420  bool flipDirection = Vector3.Dot(Vector3.forward, StartHeadRay) < 0 && FlipDirectionOnCameraForward;
421  switch (GestureData)
422  {
423  case GestureDataType.Raw:
424  CurrentDistance = DirectionVector.magnitude;
425  break;
426  case GestureDataType.Camera:
427  if (flipDirection)
428  {
429  DirectionVector = -DirectionVector;
430  }
431  CurrentDistance = Vector3.Dot(DirectionVector, MainCamera.transform.right);
432  break;
433  case GestureDataType.Aligned:
434  CurrentDistance = Vector3.Dot(DirectionVector, AlignmentVector);
435  break;
436  default:
437  break;
438  }
439 
440  CurrentPercentage = Mathf.Min(Mathf.Abs(CurrentDistance) / MaxGestureDistance, 1);
441  }
442 
443  protected virtual void Update()
444  {
445  if (KeywordGestureTimeCounter < 0)
446  {
447  if (GestureStarted)
448  {
449  KeywordGestureTimeCounter = KeywordGestureTime;
450  return;
451  }
452 
454  KeywordGestureTimeCounter += Time.deltaTime;
455  if (KeywordGestureTimeCounter > KeywordGestureTime)
456  {
457  KeywordGestureTimeCounter = KeywordGestureTime;
459  }
460 
461  CurrentGesturePosition = KeywordGestureVector * MaxGestureDistance * (KeywordGestureTimeCounter / KeywordGestureTime);
462 
463  ManipulationUpdate(StartGesturePosition, Vector3.up, StartHeadPosition, StartHeadRay, state);
464  }
465  }
466  }
467 }
GestureInteractiveData GetGestureData(Vector3 alignmentVector, float maxDistance, bool flipDirecationOnCameraForward)
Returns a data set about the current gesture information compared to a specific vector. For instance, to compare if the gesture is moving vertically or horizontally, create two instances of this data set and compare the distance for each. If the vertical percentage is greater than the horizontal percentage then the gesture is moving vertically.
float CurrentDistance
The current gesture position from the gesture origin (delta) Some of the settings above help to deter...
GestureInteractive.GestureManipulationState GestureState
Current gesture state
GestureInteractive extends Interactive and handles more advanced gesture events. On Press a gesture b...
void SetGestureVector(Vector3 gestureVector)
A way to programmatically override a gesture, used for keyword gestures.
GestureInteractiveControl receives gesture updates from GestureInteractive.
Vector3 DirectionVector
The vector from the origin position to the current gesture position
void UpdateGesture()
Update all the simplified gesture values because an update has occurred incorporates the settings...
float CurrentPercentage
The percentage of gesture distance compared to the MaxGestureDistance
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
Vector3 DirectionVectorToZPlane(Vector3 directionVector, bool flipX, bool flipY)
Aligns a gesture to the camera direction
virtual void setGestureValue(int gestureValue)
a place holder function for taking value and settings a gesture direction. Used by the keyword gestur...
Matrix4x4 GetCameraMatrix()
Get the current camera&#39;s world matrix in world space
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
virtual void ManipulationUpdate(Vector3 startGesturePosition, Vector3 currentGesturePosition, Vector3 startHeadOrigin, Vector3 startHeadRay, GestureInteractive.GestureManipulationState gestureState)
Gesture updates called by GestureInteractive
Vector3 KeywordGestureVector
animation direction for a keyword triggered gesture
GestureDataType
Dictates how the control processes data. Raw: no extra processing is done, just current gesture infor...
Vector3 StartHeadPosition
The head position when the gesture started (cached)
Vector3 StartHeadRay
the camera forward when the gesture started (cached)
Vector3 WorldForwardVector(Vector3 direction, Vector3 orientation, bool flipY=false, bool flipZ=false)
Rotates the gesture vector around a pivot point based on the camera matrix
float FlipDistanceOnFacingControl(float toFlip, Vector3 controlPosition, Vector3 controlForward)
Flips the direction based on the direction of the camera and the direction of the control...
GestureInteractiveData(Vector3 alignmentVector, float maxDistance, bool flipDirectionOnCameraForward)
Vector3 GesturePosition(Vector3 gesturePosition)
Rotates a gesture based on camera forward. Helps to take a vector in world space and rotate it to Vec...
Matrix4x4 CameraMatrix
Orientation based on the user facing direction. Can be used when translating a gesture to an object b...