AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
BoundingBoxHelper.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 System.Collections.Generic;
5 using UnityEngine;
6 
7 namespace HoloToolkit.Unity.UX
8 {
17  public class BoundingBoxHelper
18  {
19  readonly int[] face0 = { 0, 1, 3, 2 };
20  readonly int[] face1 = { 1, 5, 7, 3 };
21  readonly int[] face2 = { 5, 4, 6, 7 };
22  readonly int[] face3 = { 4, 0, 2, 6 };
23  readonly int[] face4 = { 6, 2, 3, 7 };
24  readonly int[] face5 = { 1, 0, 4, 5 };
25  readonly int[] noFaceIndices = { };
26  readonly Vector3[] noFaceVertices = { };
27 
28  private List<Vector3> rawBoundingCorners = new List<Vector3>();
29  private List<Vector3> worldBoundingCorners = new List<Vector3>();
30  private GameObject targetObject;
31  private bool rawBoundingCornersObtained = false;
32 
40  public void UpdateNonAABoundingBoxCornerPositions(GameObject target, List<Vector3> boundsPoints, LayerMask ignoreLayers)
41  {
42  if (target != targetObject || rawBoundingCornersObtained == false)
43  {
44  GetRawBBCorners(target, ignoreLayers);
45  }
46 
47  if (target == targetObject && rawBoundingCornersObtained)
48  {
49  boundsPoints.Clear();
50  for (int i = 0; i < rawBoundingCorners.Count; ++i)
51  {
52  boundsPoints.Add(target.transform.localToWorldMatrix.MultiplyPoint(rawBoundingCorners[i]));
53  }
54 
55  worldBoundingCorners.Clear();
56  worldBoundingCorners.AddRange(boundsPoints);
57  }
58  }
59 
65  public void GetRawBBCorners(GameObject target, LayerMask ignoreLayers)
66  {
67  targetObject = target;
68  rawBoundingCorners.Clear();
69  rawBoundingCornersObtained = false;
70 
71  GetUntransformedCornersFromObject(target, rawBoundingCorners, ignoreLayers);
72 
73  if (rawBoundingCorners != null && rawBoundingCorners.Count >= 4)
74  {
75  rawBoundingCornersObtained = true;
76  }
77  }
78 
84  public int[] GetFaceIndices(int index)
85  {
86  switch (index)
87  {
88  case 0:
89  return face0;
90  case 1:
91  return face1;
92  case 2:
93  return face2;
94  case 3:
95  return face3;
96  case 4:
97  return face4;
98  case 5:
99  return face5;
100  }
101 
102  return noFaceIndices;
103  }
104 
110  public Vector3[] GetFaceEdgeMidpoints(int index)
111  {
112  Vector3[] corners = GetFaceCorners(index);
113  Vector3[] midpoints = new Vector3[4];
114  midpoints[0] = (corners[0] + corners[1]) * 0.5f;
115  midpoints[1] = (corners[1] + corners[2]) * 0.5f;
116  midpoints[2] = (corners[2] + corners[3]) * 0.5f;
117  midpoints[3] = (corners[3] + corners[0]) * 0.5f;
118 
119  return midpoints;
120  }
121 
127  public Vector3 GetFaceNormal(int index)
128  {
129  int[] face = GetFaceIndices(index);
130 
131  if (face.Length == 4)
132  {
133  Vector3 ab = (worldBoundingCorners[face[1]] - worldBoundingCorners[face[0]]).normalized;
134  Vector3 ac = (worldBoundingCorners[face[2]] - worldBoundingCorners[face[0]]).normalized;
135  return Vector3.Cross(ab, ac).normalized;
136  }
137 
138  return Vector3.zero;
139  }
140 
147  public Vector3 GetFaceCentroid(int index)
148  {
149  int[] faceIndices = GetFaceIndices(index);
150 
151  if (faceIndices.Length == 4)
152  {
153  return (worldBoundingCorners[faceIndices[0]] +
154  worldBoundingCorners[faceIndices[1]] +
155  worldBoundingCorners[faceIndices[2]] +
156  worldBoundingCorners[faceIndices[3]]) * 0.25f;
157  }
158 
159  return Vector3.zero;
160  }
161 
167  public Vector3 GetFaceBottomCentroid(int index)
168  {
169  Vector3[] edgeCentroids = GetFaceEdgeMidpoints(index);
170 
171  Vector3 leastYPoint = edgeCentroids[0];
172  for (int i = 1; i < 4; ++i)
173  {
174  leastYPoint = edgeCentroids[i].y < leastYPoint.y ? edgeCentroids[i] : leastYPoint;
175  }
176  return leastYPoint;
177  }
178 
184  public Vector3[] GetFaceCorners(int index)
185  {
186  int[] faceIndices = GetFaceIndices(index);
187 
188  if (faceIndices.Length == 4)
189  {
190  Vector3[] face = new Vector3[4];
191  face[0] = worldBoundingCorners[faceIndices[0]];
192  face[1] = worldBoundingCorners[faceIndices[1]];
193  face[2] = worldBoundingCorners[faceIndices[2]];
194  face[3] = worldBoundingCorners[faceIndices[3]];
195  return face;
196  }
197 
198  return noFaceVertices;
199  }
200 
207  public int GetIndexOfForwardFace(Vector3 lookAtPoint)
208  {
209  int highestDotIndex = -1;
210  float hightestDotValue = float.MinValue;
211  for (int i = 0; i < 6; ++i)
212  {
213  Vector3 a = (lookAtPoint - GetFaceCentroid(i)).normalized;
214  Vector3 b = GetFaceNormal(i);
215  float dot = Vector3.Dot(a, b);
216  if (hightestDotValue < dot)
217  {
218  hightestDotValue = dot;
219  highestDotIndex = i;
220  }
221  }
222  return highestDotIndex;
223  }
224 
233  public static void GetNonAABoundingBoxCornerPositions(GameObject target, List<Vector3> boundsPoints, LayerMask ignoreLayers)
234  {
235  //get untransformed points
236  GetUntransformedCornersFromObject(target, boundsPoints, ignoreLayers);
237 
238  //transform the points
239  for (int i = 0; i < boundsPoints.Count; ++i)
240  {
241  boundsPoints[i] = target.transform.localToWorldMatrix.MultiplyPoint(boundsPoints[i]);
242  }
243  }
244 
251  public static void GetUntransformedCornersFromObject(GameObject target, List<Vector3> boundsPoints, LayerMask ignoreLayers)
252  {
253  GameObject clone = GameObject.Instantiate(target);
254  clone.transform.localRotation = Quaternion.identity;
255  clone.transform.position = Vector3.zero;
256  clone.transform.localScale = Vector3.one;
257  Renderer[] renderers = clone.GetComponentsInChildren<Renderer>();
258 
259  for (int i = 0; i < renderers.Length; ++i)
260  {
261  var rendererObj = renderers[i];
262  if (ignoreLayers == (1 << rendererObj.gameObject.layer | ignoreLayers))
263  {
264  continue;
265  }
266  Vector3[] corners = null;
267  rendererObj.bounds.GetCornerPositionsFromRendererBounds(ref corners);
268  AddAABoundingBoxes(boundsPoints, corners);
269  }
270 
271  GameObject.Destroy(clone);
272  }
279  public static void AddAABoundingBoxes(List<Vector3> points, Vector3[] pointsToAdd)
280  {
281  if (points.Count < 8)
282  {
283  points.Clear();
284  points.AddRange(pointsToAdd);
285  return;
286  }
287 
288  for (int i = 0; i < pointsToAdd.Length; ++i)
289  {
290  if (pointsToAdd[i].x < points[0].x)
291  {
292  points[0].Set(pointsToAdd[i].x, points[0].y, points[0].z);
293  points[1].Set(pointsToAdd[i].x, points[1].y, points[1].z);
294  points[2].Set(pointsToAdd[i].x, points[2].y, points[2].z);
295  points[3].Set(pointsToAdd[i].x, points[3].y, points[3].z);
296  }
297  if (pointsToAdd[i].x > points[4].x)
298  {
299  points[4].Set(pointsToAdd[i].x, points[4].y, points[4].z);
300  points[5].Set(pointsToAdd[i].x, points[5].y, points[5].z);
301  points[6].Set(pointsToAdd[i].x, points[6].y, points[6].z);
302  points[7].Set(pointsToAdd[i].x, points[7].y, points[7].z);
303  }
304 
305  if (pointsToAdd[i].y < points[0].y)
306  {
307  points[0].Set(points[0].x, pointsToAdd[i].y, points[0].z);
308  points[1].Set(points[1].x, pointsToAdd[i].y, points[1].z);
309  points[4].Set(points[4].x, pointsToAdd[i].y, points[4].z);
310  points[5].Set(points[5].x, pointsToAdd[i].y, points[5].z);
311  }
312  if (pointsToAdd[i].y > points[2].y)
313  {
314  points[2].Set(points[2].x, pointsToAdd[i].y, points[2].z);
315  points[3].Set(points[3].x, pointsToAdd[i].y, points[3].z);
316  points[6].Set(points[6].x, pointsToAdd[i].y, points[6].z);
317  points[7].Set(points[7].x, pointsToAdd[i].y, points[7].z);
318  }
319 
320  if (pointsToAdd[i].z < points[0].z)
321  {
322  points[0].Set(points[0].x, points[0].y, pointsToAdd[i].z);
323  points[2].Set(points[2].x, points[2].y, pointsToAdd[i].z);
324  points[6].Set(points[6].x, points[6].y, pointsToAdd[i].z);
325  points[4].Set(points[4].x, points[4].y, pointsToAdd[i].z);
326  }
327  if (pointsToAdd[i].z > points[1].z)
328  {
329  points[1].Set(points[1].x, points[1].y, pointsToAdd[i].z);
330  points[5].Set(points[5].x, points[5].y, pointsToAdd[i].z);
331  points[7].Set(points[7].x, points[7].y, pointsToAdd[i].z);
332  points[3].Set(points[3].x, points[3].y, pointsToAdd[i].z);
333  }
334  }
335  }
336  }
337 }
Vector3 GetFaceCentroid(int index)
This function returns the centroid of a face of the bounding cube of an object specified by the index...
static void GetNonAABoundingBoxCornerPositions(GameObject target, List< Vector3 > boundsPoints, LayerMask ignoreLayers)
This is the static function to call to get the non-Axis-aligned bounding box corners one time only...
Vector3 GetFaceBottomCentroid(int index)
Get the center of the bottom edge of a face of the bounding box determined by index ...
int GetIndexOfForwardFace(Vector3 lookAtPoint)
This function gets the index of the face of the bounding cube that is most facing the lookAtPoint...
Vector3 [] GetFaceEdgeMidpoints(int index)
This function returns the midpoints of each of the edges of the face of the bounding box ...
void GetRawBBCorners(GameObject target, LayerMask ignoreLayers)
This function gets the untransformed bounding box corner points of a GameObject.
void UpdateNonAABoundingBoxCornerPositions(GameObject target, List< Vector3 > boundsPoints, LayerMask ignoreLayers)
Objects that align to an target&#39;s bounding box can call this function in the object&#39;s UpdateLoop to g...
static void GetUntransformedCornersFromObject(GameObject target, List< Vector3 > boundsPoints, LayerMask ignoreLayers)
static function that performs one-time non-persistent calculation of boundingbox of object without tr...
Vector3 GetFaceNormal(int index)
Get the normal of the face of the bounding cube specified by index
Vector3 [] GetFaceCorners(int index)
This function returns the four couners of a face of a bounding cube specified by index.
int [] GetFaceIndices(int index)
this function gets the indices of the bounding cube corners that make up a face.
The BoundingBoxHelper class contains functions for getting geometric info from the non-axis-aligned b...
static void AddAABoundingBoxes(List< Vector3 > points, Vector3[] pointsToAdd)
This function expands the box defined by the first param &#39;points&#39; to include the second bounding box ...