AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SolverHandler.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 
5 using System;
6 using System.Collections.Generic;
7 using UnityEngine;
8 
9 #if UNITY_WSA
10 #if UNITY_2017_2_OR_NEWER
11 using UnityEngine.XR.WSA.Input;
12 #else
13 using UnityEngine.VR.WSA.Input;
14 #endif
15 #endif
16 
17 namespace HoloToolkit.Unity
18 {
20  {
22  {
26  Head,
30  MotionControllerLeft,
34  MotionControllerRight
35  }
36 
37  [SerializeField]
38  [Tooltip("Tracked object to calculate position and orientation from. If you want to manually override and use a scene object, use the TransformTarget field")]
39  private TrackedObjectToReferenceEnum trackedObjectToReference = TrackedObjectToReferenceEnum.Head;
40 
41  public TrackedObjectToReferenceEnum TrackedObjectToReference
42  {
43  get { return trackedObjectToReference; }
44  set
45  {
46  if (trackedObjectToReference != value)
47  {
48  trackedObjectToReference = value;
49  OnControllerLost();
50  AttachToNewTrackedObject();
51  }
52  }
53  }
54 
55  [SerializeField]
56  [Tooltip("Add an additional offset of the tracked object to base the solver on. Useful for tracking something like a halo position above your head or off the side of a controller. Cannot be updated once Play begins.")]
57  private Vector3 additionalOffset;
58 
59  [SerializeField]
60  [Tooltip("Add an additional rotation on top of the tracked object. Useful for tracking what is essentially the up or right/left vectors. Cannot be updated once Play begins.")]
61  private Vector3 additionalRotation;
62 
63  public Vector3 AdditionalOffset
64  {
65  get { return additionalOffset; }
66  set
67  {
68  additionalOffset = value;
69  TrackTransform(TransformTarget);
70  }
71  }
72 
73  public Vector3 AdditionalRotation
74  {
75  get { return additionalRotation; }
76  set
77  {
78  additionalRotation = value;
79  TrackTransform(TransformTarget);
80  }
81  }
82 
83  [SerializeField]
84  [Tooltip("Manual override for TrackedObjectToReference if you want to use a scene object. Leave empty if you want to use Head or Motion controllers")]
85  private Transform transformTarget;
86 
87  public Transform TransformTarget
88  {
89  get { return transformTarget; }
90  set { transformTarget = value; }
91  }
92 
93  public Vector3 GoalPosition { get; set; }
94 
95  public Quaternion GoalRotation { get; set; }
96 
97  public Vector3 GoalScale { get; set; }
98 
99  public Vector3Smoothed AltScale { get; set; }
100 
101  public float DeltaTime { get; set; }
102 
103  private float LastUpdateTime { get; set; }
104 
105  protected List<Solver> m_Solvers = new List<Solver>();
106 
107  [SerializeField]
108  private bool updateSolvers = true;
109  public bool UpdateSolvers { get { return updateSolvers; } set { updateSolvers = value; } }
110 
111  private GameObject transformWithOffset;
112 
113  private void Awake()
114  {
115  m_Solvers.AddRange(GetComponents<Solver>());
116 
117  GoalScale = Vector3.one;
118  AltScale = new Vector3Smoothed(Vector3.one, 0.1f);
119  DeltaTime = 0.0f;
120 
121  //TransformTarget overrides TrackedObjectToReference
122  if (!TransformTarget)
123  {
124  AttachToNewTrackedObject();
125  }
126  }
127 
128  private void Update()
129  {
130  DeltaTime = Time.realtimeSinceStartup - LastUpdateTime;
131  LastUpdateTime = Time.realtimeSinceStartup;
132  }
133 
134  private void LateUpdate()
135  {
136  if (UpdateSolvers)
137  {
138  for (int i = 0; i < m_Solvers.Count; ++i)
139  {
140  Solver solver = m_Solvers[i];
141 
142  if (solver.enabled)
143  {
144  solver.SolverUpdate();
145  }
146  }
147  }
148  }
149 
150  protected override void OnDestroy()
151  {
152  base.OnDestroy();
153 
154  if (transformWithOffset != null)
155  {
156  Destroy(transformWithOffset);
157  }
158  }
159 
160  protected override void OnControllerFound()
161  {
162  if (!TransformTarget)
163  {
164  TrackTransform(ElementTransform);
165  }
166  }
167 
168  protected override void OnControllerLost()
169  {
170  TransformTarget = null;
171 
172  if (transformWithOffset != null)
173  {
174  Destroy(transformWithOffset);
175  transformWithOffset = null;
176  }
177  }
178 
179  public virtual void AttachToNewTrackedObject()
180  {
181  switch (TrackedObjectToReference)
182  {
184 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
185  // No need to search for a controller if we've already attached to the head.
186  Handedness = InteractionSourceHandedness.Unknown;
187 #endif
188  TrackTransform(CameraCache.Main.transform);
189  break;
190  case TrackedObjectToReferenceEnum.MotionControllerLeft:
191 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
192  Handedness = InteractionSourceHandedness.Left;
193 #endif
194  break;
195  case TrackedObjectToReferenceEnum.MotionControllerRight:
196 #if UNITY_WSA && UNITY_2017_2_OR_NEWER
197  Handedness = InteractionSourceHandedness.Right;
198 #endif
199  break;
200  }
201  }
202 
203  private void TrackTransform(Transform newTrackedTransform)
204  {
205  TransformTarget = MakeOffsetTransform(newTrackedTransform);
206  }
207 
208  private Transform MakeOffsetTransform(Transform parentTransform)
209  {
210  if (transformWithOffset == null)
211  {
212  transformWithOffset = new GameObject();
213  transformWithOffset.transform.parent = parentTransform;
214  }
215 
216  transformWithOffset.transform.localPosition = AdditionalOffset;
217  transformWithOffset.transform.localRotation = Quaternion.Euler(AdditionalRotation);
218  transformWithOffset.name = string.Format("{0} on {1} with offset {2}, {3}", gameObject.name, TrackedObjectToReference.ToString(), AdditionalOffset, AdditionalRotation);
219  // In order to account for the reversed normals due to the glTF coordinate system change, we need to provide rotated attachment points.
220  transformWithOffset.transform.Rotate(0, 180, 0);
221 
222  return transformWithOffset.transform;
223  }
224 
225  [Serializable]
226  public struct Vector3Smoothed
227  {
228  public Vector3 Current { get; set; }
229  public Vector3 Goal { get; set; }
230  public float SmoothTime { get; set; }
231 
232  public Vector3Smoothed(Vector3 value, float smoothingTime) : this()
233  {
234  Current = value;
235  Goal = value;
236  SmoothTime = smoothingTime;
237  }
238 
239  public void Update(float deltaTime)
240  {
241  Current = Vector3.Lerp(Current, Goal, (Math.Abs(SmoothTime) < Mathf.Epsilon) ? 1.0f : deltaTime / SmoothTime);
242  }
243 
244  public void SetGoal(Vector3 newGoal)
245  {
246  Goal = newGoal;
247  }
248  }
249 
250  [Serializable]
251  public struct QuaternionSmoothed
252  {
253  public Quaternion Current { get; set; }
254  public Quaternion Goal { get; set; }
255  public float SmoothTime { get; set; }
256 
257  public QuaternionSmoothed(Quaternion value, float smoothingTime) : this()
258  {
259  Current = value;
260  Goal = value;
261  SmoothTime = smoothingTime;
262  }
263 
264  public void Update(float deltaTime)
265  {
266  Current = Quaternion.Slerp(Current, Goal, (Math.Abs(SmoothTime) < Mathf.Epsilon) ? 1.0f : deltaTime / SmoothTime);
267  }
268 
269  public void SetGoal(Quaternion newGoal)
270  {
271  Goal = newGoal;
272  }
273  }
274  }
275 }
Vector3Smoothed(Vector3 value, float smoothingTime)
SolverBase is the base abstract class for all Solvers to derive from. It provides state tracking...
Definition: Solver.cs:15
QuaternionSmoothed(Quaternion value, float smoothingTime)
virtual void AttachToNewTrackedObject()
abstract void SolverUpdate()
override void OnControllerLost()
Override this method to act when the correct controller is actually lost. This provides similar funct...
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
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
override void OnControllerFound()
Override this method to act when the correct controller is actually found. This provides similar func...
ControllerFinder is a base class providing simple event handling for getting/releasing MotionControll...