AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
RaycastHelper.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // Licensed under the MIT License. See LICENSE in the project root for license information.
4 //
5 using System.Collections.Generic;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity
9 {
10  public static class RaycastHelper
11  {
12  public static bool DebugEnabled = false;
13 
14  public delegate bool RaycastFunc(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask, out RaycastResultHelper result);
15 
16  public static bool First(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask, out RaycastResultHelper result)
17  {
18  result = default(RaycastResultHelper);
19 
20  RaycastHit hit;
21  bool hitSomething = false;
22 
23  // Check to see if the ray cast hits any of the requested Unity layers
24  if (layerMask != 0 &&
25  UnityEngine.Physics.Raycast(origin, direction, out hit, distance, layerMask))
26  {
27  result = new RaycastResultHelper(hit, layerMask);
28 
29  hitSomething = true;
30  }
31 
32  return hitSomething;
33  }
34 
35  public static bool SphereFirst(Vector3 origin, Vector3 direction, float radius, float distance, LayerMask layerMask, out RaycastResultHelper result)
36  {
37  result = default(RaycastResultHelper);
38 
39  RaycastHit hit;
40  bool hitSomething = false;
41 
42  // Check to see if the ray cast hits any of the requested Unity layers
43  if (layerMask != 0 &&
44  UnityEngine.Physics.SphereCast(origin, radius, direction, out hit, distance, layerMask))
45  {
46  result = new RaycastResultHelper(hit, layerMask);
47 
48  hitSomething = true;
49  }
50 
51  return hitSomething;
52  }
53 
54  public static List<RaycastResultHelper> All(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask)
55  {
56  return All(origin, direction, distance, layerMask, null);
57  }
58 
59  public static List<RaycastResultHelper> All(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask, List<Collider> movedColliders)
60  {
61  // Check to see if the ray cast hits any of the requested Unity layers
62  List<RaycastResultHelper> results = null;
63  if (layerMask != 0)
64  {
65  var raycastHits = UnityEngine.Physics.RaycastAll(origin, direction, distance, layerMask);
66  if (raycastHits != null)
67  {
68  results = new List<RaycastResultHelper>(raycastHits.Length);
69  foreach (var raycastHit in raycastHits)
70  {
71  results.Add(new RaycastResultHelper(raycastHit, layerMask));
72  }
73  }
74  }
75 
76  // If we have colliders that have moved, then remove them from the results list and redo the raycast.
77  if (movedColliders != null)
78  {
79  RaycastHit hitInfo;
80  Ray ray = new Ray(origin, direction);
81  foreach (var collider in movedColliders)
82  {
83  if ((collider.gameObject.layer & layerMask) != 0)
84  {
85  int colliderIndex = results.FindIndex(x => x.Collider == collider);
86 
87  if (collider.Raycast(ray, out hitInfo, distance))
88  {
89  if (colliderIndex >= 0)
90  {
91  results[colliderIndex] = new RaycastResultHelper(hitInfo, layerMask);
92  }
93  else
94  {
95  results.Add(new RaycastResultHelper(hitInfo, layerMask));
96  }
97  }
98  else if (colliderIndex >= 0)
99  {
100  results.RemoveAt(colliderIndex);
101  }
102  }
103  }
104  }
105 
106  // Unity doesn't return hit results in any particular order, so we need to sort them to closest first.
107  if (results != null)
108  {
109  results.Sort((x, y) => x.Distance < y.Distance ? -1 : 1);
110  }
111 
112  return results;
113  }
114 
115  public static Vector3 GetBoxColliderExtents(BoxCollider boxCollider)
116  {
117  return boxCollider.size;
118  }
119 
120  // raysPerEdge should be odd
121  public static bool CastBoxExtents(Vector3 extents, Vector3 targetPosition, Matrix4x4 trs, Ray ray, float maxDistance, LayerMask surface, RaycastFunc raycastFunc, int raysPerEdge, bool ortho, out Vector3[] points, out Vector3[] normals, out bool[] hits)
122  {
123  bool debugEnabled = DebugEnabled;
124  if (debugEnabled)
125  {
126  Debug.DrawLine(ray.origin, ray.origin + ray.direction * 10.0f, Color.green);
127  }
128 
129  extents /= (raysPerEdge - 1);
130 
131  int halfRaysPerEdge = (raysPerEdge - 1) / 2;
132  int numRays = raysPerEdge * raysPerEdge;
133 
134  bool hitSomething = false;
135 
136  points = new Vector3[numRays];
137  normals = new Vector3[numRays];
138  hits = new bool[numRays];
139 
140  int index = 0;
141 
142  for (int x = -halfRaysPerEdge; x <= halfRaysPerEdge; x += 1)
143  {
144  for (int y = -halfRaysPerEdge; y <= halfRaysPerEdge; y += 1)
145  {
146  Vector3 offset = trs.MultiplyVector(new Vector3(x * extents.x, y * extents.y, 0));
147 
148  Vector3 origin = ray.origin;
149  Vector3 direction = (targetPosition + offset) - ray.origin;
150 
151  if (ortho)
152  {
153  origin += offset;
154  direction = ray.direction;
155  }
156 
157  RaycastResultHelper rayHit;
158  hits[index] = raycastFunc(origin, direction, maxDistance, surface, out rayHit);
159 
160  if (hits[index])
161  {
162  hitSomething = true;
163  points[index] = rayHit.Point;
164  normals[index] = rayHit.Normal;
165 
166  if (debugEnabled)
167  {
168  Debug.DrawLine(origin, points[index], Color.yellow);
169  }
170  }
171  else
172  {
173  if (debugEnabled)
174  {
175  Debug.DrawLine(origin, origin + direction * 3.0f, Color.gray);
176  }
177  }
178 
179  index++;
180  }
181  }
182 
183  return hitSomething;
184  }
185  }
186 }
static bool First(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask, out RaycastResultHelper result)
static bool SphereFirst(Vector3 origin, Vector3 direction, float radius, float distance, LayerMask layerMask, out RaycastResultHelper result)
static List< RaycastResultHelper > All(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask, List< Collider > movedColliders)
static Vector3 GetBoxColliderExtents(BoxCollider boxCollider)
static bool CastBoxExtents(Vector3 extents, Vector3 targetPosition, Matrix4x4 trs, Ray ray, float maxDistance, LayerMask surface, RaycastFunc raycastFunc, int raysPerEdge, bool ortho, out Vector3[] points, out Vector3[] normals, out bool[] hits)
static List< RaycastResultHelper > All(Vector3 origin, Vector3 direction, float distance, LayerMask layerMask)