AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SimpleTagalong.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  [RequireComponent(typeof(BoxCollider), typeof(Interpolator))]
13  public class SimpleTagalong : MonoBehaviour
14  {
15  // Simple Tagalongs seek to stay at a fixed distance from the Camera.
16  [Tooltip("The distance in meters from the camera for the Tagalong to seek when updating its position.")]
17  public float TagalongDistance = 2.0f;
18  [Tooltip("If true, forces the Tagalong to be TagalongDistance from the camera, even if it didn't need to move otherwise.")]
19  public bool EnforceDistance = true;
20 
21  [Tooltip("The speed at which to move the Tagalong when updating its position (meters/second).")]
22  public float PositionUpdateSpeed = 9.8f;
23  [Tooltip("When true, the Tagalong's motion is smoothed.")]
24  public bool SmoothMotion = true;
25  [Range(0.0f, 1.0f), Tooltip("The factor applied to the smoothing algorithm. 1.0f is super smooth. But slows things down a lot.")]
26  public float SmoothingFactor = 0.75f;
27 
28  // The BoxCollider represents the volume of the object that is tagging
29  // along. It is a required component.
30  protected BoxCollider tagalongCollider;
31 
32  // The Interpolator is a helper class that handles various changes to an
33  // object's transform. It is used by Tagalong to adjust the object's
34  // transform.position.
36 
37  // This is an array of planes that define the camera's view frustum along
38  // with some helpful indices into the array. The array is updated each
39  // time through FixedUpdate().
40  protected Plane[] frustumPlanes;
41  protected const int frustumLeft = 0;
42  protected const int frustumRight = 1;
43  protected const int frustumBottom = 2;
44  protected const int frustumTop = 3;
45 
46  protected virtual void Start()
47  {
48  // Make sure the Tagalong object has a BoxCollider.
49  tagalongCollider = GetComponent<BoxCollider>();
50 
51  // Get the Interpolator component and set some default parameters for
52  // it. These parameters can be adjusted in Unity's Inspector as well.
53  interpolator = gameObject.GetComponent<Interpolator>();
54  interpolator.SmoothLerpToTarget = SmoothMotion;
55  interpolator.SmoothPositionLerpRatio = SmoothingFactor;
56  }
57 
58  protected virtual void Update()
59  {
60  Camera mainCamera = CameraCache.Main;
61  // Retrieve the frustum planes from the camera.
62  frustumPlanes = GeometryUtility.CalculateFrustumPlanes(mainCamera);
63 
64  // Determine if the Tagalong needs to move based on whether its
65  // BoxCollider is in or out of the camera's view frustum.
66  Vector3 tagalongTargetPosition;
67  if (CalculateTagalongTargetPosition(transform.position, out tagalongTargetPosition))
68  {
69  // Derived classes will use the same Interpolator and may have
70  // adjusted its PositionUpdateSpeed for some other purpose.
71  // Restore the value we care about and tell the Interpolator
72  // to move the Tagalong to its new target position.
73  interpolator.PositionPerSecond = PositionUpdateSpeed;
74  interpolator.SetTargetPosition(tagalongTargetPosition);
75  }
76  else if (!interpolator.Running && EnforceDistance)
77  {
78  // If the Tagalong is inside the camera's view frustum, and it is
79  // supposed to stay a fixed distance from the camera, force the
80  // tagalong to that location (without using the Interpolator).
81  Ray ray = new Ray(mainCamera.transform.position, transform.position - mainCamera.transform.position);
82  transform.position = ray.GetPoint(TagalongDistance);
83  }
84  }
85 
93  protected virtual bool CalculateTagalongTargetPosition(Vector3 fromPosition, out Vector3 toPosition)
94  {
95  // Check to see if any part of the Tagalong's BoxCollider's bounds is
96  // inside the camera's view frustum. Note, the bounds used are an Axis
97  // Aligned Bounding Box (AABB).
98  bool needsToMove = !GeometryUtility.TestPlanesAABB(frustumPlanes, tagalongCollider.bounds);
99  Transform cameraTransform = CameraCache.Main.transform;
100 
101  // If we already know we don't need to move, bail out early.
102  if (!needsToMove)
103  {
104  toPosition = fromPosition;
105  return false;
106  }
107 
108  // Calculate a default position where the Tagalong should go. In this
109  // case TagalongDistance from the camera along the gaze vector.
110  toPosition = cameraTransform.position + cameraTransform.forward * TagalongDistance;
111 
112  // Create a Ray and set it's origin to be the default toPosition that
113  // was calculated above.
114  Ray ray = new Ray(toPosition, Vector3.zero);
115  Plane plane = new Plane();
116  float distanceOffset = 0f;
117 
118  // Determine if the Tagalong needs to move to the right or the left
119  // to get back inside the camera's view frustum. The normals of the
120  // planes that make up the camera's view frustum point inward.
121  bool moveRight = frustumPlanes[frustumLeft].GetDistanceToPoint(fromPosition) < 0;
122  bool moveLeft = frustumPlanes[frustumRight].GetDistanceToPoint(fromPosition) < 0;
123  if (moveRight)
124  {
125  // If the Tagalong needs to move to the right, that means it is to
126  // the left of the left frustum plane. Remember that plane and set
127  // our Ray's direction to point towards that plane (remember the
128  // Ray's origin is already inside the view frustum.
129  plane = frustumPlanes[frustumLeft];
130  ray.direction = -cameraTransform.right;
131  }
132  else if (moveLeft)
133  {
134  // Apply similar logic to above for the case where the Tagalong
135  // needs to move to the left.
136  plane = frustumPlanes[frustumRight];
137  ray.direction = cameraTransform.right;
138  }
139  if (moveRight || moveLeft)
140  {
141  // If the Tagalong needed to move in the X direction, cast a Ray
142  // from the default position to the plane we are working with.
143  plane.Raycast(ray, out distanceOffset);
144 
145  // Get the point along that ray that is on the plane and update
146  // the x component of the Tagalong's desired position.
147  toPosition.x = ray.GetPoint(distanceOffset).x;
148  }
149 
150  // Similar logic follows below for determining if and how the
151  // Tagalong would need to move up or down.
152  bool moveDown = frustumPlanes[frustumTop].GetDistanceToPoint(fromPosition) < 0;
153  bool moveUp = frustumPlanes[frustumBottom].GetDistanceToPoint(fromPosition) < 0;
154  if (moveDown)
155  {
156  plane = frustumPlanes[frustumTop];
157  ray.direction = cameraTransform.up;
158  }
159  else if (moveUp)
160  {
161  plane = frustumPlanes[frustumBottom];
162  ray.direction = -cameraTransform.up;
163  }
164  if (moveUp || moveDown)
165  {
166  plane.Raycast(ray, out distanceOffset);
167  toPosition.y = ray.GetPoint(distanceOffset).y;
168  }
169 
170  // Create a ray that starts at the camera and points in the direction
171  // of the calculated toPosition.
172  ray = new Ray(cameraTransform.position, toPosition - cameraTransform.position);
173 
174  // Find the point along that ray that is the right distance away and
175  // update the calculated toPosition to be that point.
176  toPosition = ray.GetPoint(TagalongDistance);
177 
178  // If we got here, needsToMove will be true.
179  return needsToMove;
180  }
181  }
182 }
void SetTargetPosition(Vector3 target)
Sets the target position for the transform and if position wasn&#39;t already animating, fires the InterpolationStarted event.
A Tagalong that stays at a fixed distance from the camera and always seeks to have a part of itself i...
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
A MonoBehaviour that interpolates a transform&#39;s position, rotation or scale.
Definition: Interpolator.cs:11
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 bool CalculateTagalongTargetPosition(Vector3 fromPosition, out Vector3 toPosition)
Determines if the Tagalong needs to move based on the provided position.
bool Running
True if position, rotation or scale are animating; false otherwise.
Definition: Interpolator.cs:96