AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SolverOrbital.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 
6 namespace HoloToolkit.Unity
7 {
12  public class SolverOrbital : Solver
13  {
15  {
19  FollowTrackedObject,
23  FaceTrackedObject,
27  YawOnly,
31  Unmodified,
35  CameraFacing,
39  CameraAligned,
40  }
41 
42  #region public members
43  [Tooltip("The desired orientation of this object. Default sets the object to face the TrackedObject/TargetTransform. CameraFacing sets the object to always face the user.")]
44  [SerializeField]
45  private OrientationReferenceEnum orientation = OrientationReferenceEnum.FollowTrackedObject;
46 
50  public OrientationReferenceEnum Orientation
51  {
52  get { return orientation; }
53  set { orientation = value; }
54  }
55 
56  [Tooltip("XYZ offset for this object in relation to the TrackedObject/TargetTransform. Mixing local and world offsets is not recommended.")]
57  [SerializeField]
58  private Vector3 localOffset = new Vector3(0,-1,1);
59 
63  public Vector3 LocalOffset
64  {
65  get { return localOffset; }
66  set { localOffset = value; }
67  }
68 
69  [Tooltip("XYZ offset for this object in worldspace, best used with the YawOnly orientation. Mixing local and world offsets is not recommended.")]
70  [SerializeField]
71  private Vector3 worldOffset = Vector3.zero;
72 
76  public Vector3 WorldOffset
77  {
78  get { return worldOffset; }
79  set { worldOffset = value; }
80  }
81 
82  [Tooltip("Lock the rotation to a specified number of steps around the tracked object.")]
83  [SerializeField]
84  private bool useAngleSteppingForWorldOffset = false;
85 
89  public bool UseAngleSteppingForWorldOffset
90  {
91  get { return useAngleSteppingForWorldOffset; }
92  set { useAngleSteppingForWorldOffset = value; }
93  }
94 
95  [Tooltip("TetherAngleSteps is the division of steps this object can tether to. Higher the number, the more snapple steps.")]
96  [Range(2, 24)]
97  [SerializeField]
98  private int tetherAngleSteps = 6;
102  public int TetherAngleSteps
103  {
104  get { return tetherAngleSteps;}
105  set
106  {
107  if (value > 24 || value < 2)
108  {
109  Debug.LogError("TetherAngleSteps was set to a size larger than it's max range. Clamping to a valid value.");
110  }
111  tetherAngleSteps = Mathf.Clamp(value, 2, 24);
112  }
113  }
114  #endregion
115 
116  public override void SolverUpdate()
117  {
118  Vector3 desiredPos = solverHandler.TransformTarget != null ? solverHandler.TransformTarget.position : Vector3.zero;
119 
120  Quaternion targetRot = solverHandler.TransformTarget != null ? solverHandler.TransformTarget.rotation : Quaternion.Euler(0, 1, 0);
121  Quaternion yawOnlyRot = Quaternion.Euler(0, targetRot.eulerAngles.y, 0);
122  desiredPos = desiredPos + (SnapToTetherAngleSteps(targetRot) * LocalOffset);
123  desiredPos = desiredPos + (SnapToTetherAngleSteps(yawOnlyRot) * WorldOffset);
124 
125  Quaternion desiredRot = CalculateDesiredRotation(desiredPos);
126 
127  GoalPosition = desiredPos;
128  GoalRotation = desiredRot;
129 
130  UpdateWorkingPosToGoal();
131  UpdateWorkingRotToGoal();
132  }
133 
134 
135  private Quaternion SnapToTetherAngleSteps(Quaternion RotationToSnap)
136  {
137  if (!UseAngleSteppingForWorldOffset)
138  {
139  return RotationToSnap;
140  }
141 
142  float stepAngle = 360f / TetherAngleSteps;
143  int numberOfSteps = Mathf.RoundToInt(solverHandler.TransformTarget.transform.localEulerAngles.y / stepAngle);
144 
145  float newAngle = stepAngle * numberOfSteps;
146 
147  return Quaternion.Euler(RotationToSnap.eulerAngles.x, newAngle, RotationToSnap.eulerAngles.z);
148  }
149 
150  private Quaternion CalculateDesiredRotation( Vector3 desiredPos )
151  {
152  Quaternion desiredRot;
153 
154  switch (orientation)
155  {
156  case OrientationReferenceEnum.YawOnly:
157  float targetYRotation;
158  if (solverHandler.TransformTarget != null)
159  {
160  targetYRotation = solverHandler.TransformTarget.eulerAngles.y;
161  }
162  else
163  {
164  targetYRotation = 1;
165  }
166  desiredRot = Quaternion.Euler(0f, targetYRotation, 0f);
167  break;
168  case OrientationReferenceEnum.Unmodified:
169  desiredRot = transform.rotation;
170  break;
171  case OrientationReferenceEnum.CameraAligned:
172  desiredRot = CameraCache.Main.transform.rotation;
173  break;
174  case OrientationReferenceEnum.FaceTrackedObject:
175  desiredRot = Quaternion.LookRotation(solverHandler.TransformTarget.position - desiredPos);
176  break;
177  case OrientationReferenceEnum.CameraFacing:
178  desiredRot = Quaternion.LookRotation(CameraCache.Main.transform.position - desiredPos);
179  break;
180  default:
181  case OrientationReferenceEnum.FollowTrackedObject:
182  if (solverHandler.TransformTarget != null)
183  {
184  desiredRot = solverHandler.TransformTarget.rotation;
185  }
186  else
187  {
188  desiredRot = Quaternion.identity;
189  }
190  break;
191  }
192 
193  if (UseAngleSteppingForWorldOffset)
194  {
195  desiredRot = SnapToTetherAngleSteps(desiredRot);
196  }
197  return desiredRot;
198  }
199  }
200 }
SolverBase is the base abstract class for all Solvers to derive from. It provides state tracking...
Definition: Solver.cs:15
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
SolverOrbital provides a solver that offsets from the TrackedObject/TargetTransform. Adjusting "LerpTime" properties changes how quickly the object moves to the TrackedObject/TargetTransform&#39;s position.