AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SpatialMappingSource.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;
5 using System.Collections.Generic;
6 using System.Collections.ObjectModel;
7 using UnityEngine;
8 using UnityEngine.Rendering;
9 
10 namespace HoloToolkit.Unity.SpatialMapping
11 {
12  public class SpatialMappingSource : MonoBehaviour
13  {
17  public struct SurfaceObject
18  {
19  public int ID;
20  public GameObject Object;
21  public MeshRenderer Renderer;
22  public MeshFilter Filter;
23  public MeshCollider Collider;
24  }
25 
26  public struct SurfaceUpdate
27  {
30  }
31 
35  public ReadOnlyCollection<SurfaceObject> SurfaceObjects
36  {
37  get { return surfaceObjects; }
38  }
39 
40  public event EventHandler<DataEventArgs<SurfaceObject>> SurfaceAdded;
41  public event EventHandler<DataEventArgs<SurfaceUpdate>> SurfaceUpdated;
42  public event EventHandler<DataEventArgs<SurfaceObject>> SurfaceRemoved;
43  public event EventHandler<EventArgs> RemovingAllSurfaces;
44 
49  protected readonly Type[] componentsRequiredForSurfaceMesh =
50  {
51  typeof(MeshFilter),
52  typeof(MeshRenderer),
53  typeof(MeshCollider)
54  };
55 
59  protected virtual Material RenderMaterial { get { return SpatialMappingManager.Instance.SurfaceMaterial; } }
60 
61  private readonly List<SurfaceObject> surfaceObjectsWriteable;
62  private readonly ReadOnlyCollection<SurfaceObject> surfaceObjects;
63 
65  {
66  surfaceObjectsWriteable = new List<SurfaceObject>();
67  surfaceObjects = new ReadOnlyCollection<SurfaceObject>(surfaceObjectsWriteable);
68  }
69 
70  protected virtual void Awake()
71  {
72  // Nothing.
73  }
74 
86  Mesh mesh,
87  string objectName,
88  Transform parentObject,
89  int meshID = 0,
90  bool? drawVisualMeshesOverride = null,
91  bool? castShadowsOverride = null
92  )
93  {
94  SurfaceObject surfaceObject = new SurfaceObject();
95  surfaceObject.ID = meshID;
96 
97  surfaceObject.Object = new GameObject(objectName, componentsRequiredForSurfaceMesh);
98  surfaceObject.Object.transform.SetParent(parentObject);
99  surfaceObject.Object.layer = SpatialMappingManager.Instance.PhysicsLayer;
100 
101  surfaceObject.Filter = surfaceObject.Object.GetComponent<MeshFilter>();
102  surfaceObject.Filter.sharedMesh = mesh;
103 
104  surfaceObject.Renderer = surfaceObject.Object.GetComponent<MeshRenderer>();
105  surfaceObject.Renderer.sharedMaterial = RenderMaterial;
106  surfaceObject.Renderer.enabled = (drawVisualMeshesOverride ?? SpatialMappingManager.Instance.DrawVisualMeshes);
107  surfaceObject.Renderer.shadowCastingMode = ((castShadowsOverride ?? SpatialMappingManager.Instance.CastShadows) ? ShadowCastingMode.On : ShadowCastingMode.Off);
108 
109  surfaceObject.Collider = surfaceObject.Object.GetComponent<MeshCollider>();
110 
111  // Reset the surface mesh collider to fit the updated mesh.
112  // Unity tribal knowledge indicates that to change the mesh assigned to a
113  // mesh collider, the mesh must first be set to null. Presumably there
114  // is a side effect in the setter when setting the shared mesh to null.
115  surfaceObject.Collider.sharedMesh = null;
116  surfaceObject.Collider.sharedMesh = surfaceObject.Filter.sharedMesh;
117 
118  return surfaceObject;
119  }
120 
125  protected void AddSurfaceObject(SurfaceObject toAdd)
126  {
127  surfaceObjectsWriteable.Add(toAdd);
128 
129  var handlers = SurfaceAdded;
130  if (handlers != null)
131  {
132  handlers(this, DataEventArgs.Create(toAdd));
133  }
134  }
135 
143  protected SurfaceObject? UpdateOrAddSurfaceObject(SurfaceObject toUpdateOrAdd, bool destroyGameObjectIfReplaced = true, bool destroyMeshesIfReplaced = true)
144  {
145  SurfaceObject? replaced = null;
146 
147  for (int iSurface = 0; iSurface < surfaceObjectsWriteable.Count; iSurface++)
148  {
149  SurfaceObject existing = surfaceObjectsWriteable[iSurface];
150 
151  if (existing.ID == toUpdateOrAdd.ID)
152  {
153  surfaceObjectsWriteable[iSurface] = toUpdateOrAdd;
154 
155  var handlers = SurfaceUpdated;
156  if (handlers != null)
157  {
158  handlers(this, DataEventArgs.Create(new SurfaceUpdate { Old = existing, New = toUpdateOrAdd }));
159  }
160 
161  CleanUpSurface(
162  existing,
163  destroyGameObjectIfReplaced,
164  destroyMeshesIfReplaced,
165  objectToPreserve: toUpdateOrAdd.Object,
166  meshToPreserveA: toUpdateOrAdd.Filter.sharedMesh,
167  meshToPreserveB: toUpdateOrAdd.Collider.sharedMesh
168  );
169 
170  replaced = existing;
171  break;
172  }
173  }
174 
175  if (replaced == null)
176  {
177  AddSurfaceObject(toUpdateOrAdd);
178  }
179 
180  return replaced;
181  }
182 
190  protected SurfaceObject? RemoveSurfaceIfFound(int surfaceID, bool destroyGameObject = true, bool destroyMeshes = true)
191  {
192  SurfaceObject? removed = null;
193 
194  for (int iSurface = 0; iSurface < surfaceObjectsWriteable.Count; iSurface++)
195  {
196  SurfaceObject surface = surfaceObjectsWriteable[iSurface];
197 
198  if (surface.ID == surfaceID)
199  {
200  surfaceObjectsWriteable.RemoveAt(iSurface);
201 
202  var handlers = SurfaceRemoved;
203  if (handlers != null)
204  {
205  handlers(this, DataEventArgs.Create(surface));
206  }
207 
208  CleanUpSurface(surface, destroyGameObject, destroyMeshes);
209 
210  removed = surface;
211  break;
212  }
213  }
214 
215  return removed;
216  }
217 
227  protected void CleanUpSurface(
228  SurfaceObject surface,
229  bool destroyGameObject = true,
230  bool destroyMeshes = true,
231  GameObject objectToPreserve = null,
232  Mesh meshToPreserveA = null,
233  Mesh meshToPreserveB = null
234  )
235  {
236  if (destroyGameObject
237  && (surface.Object != null)
238  && (surface.Object != objectToPreserve)
239  )
240  {
241  Destroy(surface.Object);
242  Debug.Assert(surface.GetType().IsValueType(), "If surface is no longer a value type, you should probably set surface.Object to null.");
243  }
244 
245  Mesh filterMesh = surface.Filter.sharedMesh;
246  Mesh colliderMesh = surface.Collider.sharedMesh;
247 
248  if (destroyMeshes
249  && (filterMesh != null)
250  && (filterMesh != meshToPreserveA)
251  && (filterMesh != meshToPreserveB)
252  )
253  {
254  Destroy(filterMesh);
255  surface.Filter.sharedMesh = null;
256  }
257 
258  if (destroyMeshes
259  && (colliderMesh != null)
260  && (colliderMesh != filterMesh)
261  && (colliderMesh != meshToPreserveA)
262  && (colliderMesh != meshToPreserveB)
263  )
264  {
265  Destroy(colliderMesh);
266  surface.Collider.sharedMesh = null;
267  }
268  }
269 
275  protected void Cleanup(bool destroyGameObjects = true, bool destroyMeshes = true)
276  {
277  var handlers = RemovingAllSurfaces;
278  if (handlers != null)
279  {
280  handlers(this, EventArgs.Empty);
281  }
282 
283  for (int index = 0; index < surfaceObjectsWriteable.Count; index++)
284  {
285  CleanUpSurface(surfaceObjectsWriteable[index], destroyGameObjects, destroyMeshes);
286  }
287  surfaceObjectsWriteable.Clear();
288  }
289 
294  public virtual List<MeshFilter> GetMeshFilters()
295  {
296  List<MeshFilter> meshFilters = new List<MeshFilter>();
297 
298  for (int index = 0; index < surfaceObjectsWriteable.Count; index++)
299  {
300  if (surfaceObjectsWriteable[index].Filter != null &&
301  surfaceObjectsWriteable[index].Filter.sharedMesh != null &&
302  surfaceObjectsWriteable[index].Filter.sharedMesh.vertexCount > 2)
303  {
304  meshFilters.Add(surfaceObjectsWriteable[index].Filter);
305  }
306  }
307 
308  return meshFilters;
309  }
310 
315  public virtual List<MeshRenderer> GetMeshRenderers()
316  {
317  List<MeshRenderer> meshRenderers = new List<MeshRenderer>();
318 
319  for (int index = 0; index < surfaceObjectsWriteable.Count; index++)
320  {
321  if (surfaceObjectsWriteable[index].Renderer != null)
322  {
323  meshRenderers.Add(surfaceObjectsWriteable[index].Renderer);
324  }
325  }
326 
327  return meshRenderers;
328  }
329 
334  public void SaveSpatialMeshes(string fileName)
335  {
336  MeshSaver.Save(fileName, GetMeshFilters());
337  }
338  }
339 }
MeshSaver is a static class containing methods used for saving and loading meshes.
Definition: MeshSaver.cs:20
void SaveSpatialMeshes(string fileName)
Saves all the currently created spatial source meshes in world space.
void AddSurfaceObject(SurfaceObject toAdd)
Add the surface to SurfaceObjects.
EventHandler< DataEventArgs< SurfaceUpdate > > SurfaceUpdated
static string Save(string fileName, IEnumerable< MeshFilter > meshFilters)
Transforms all the mesh vertices into world position before saving to file.
Definition: MeshSaver.cs:49
virtual List< MeshFilter > GetMeshFilters()
Gets all mesh filters that have a valid mesh.
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
SurfaceObject CreateSurfaceObject(Mesh mesh, string objectName, Transform parentObject, int meshID=0, bool? drawVisualMeshesOverride=null, bool? castShadowsOverride=null)
Create a new surface object.
void Cleanup(bool destroyGameObjects=true, bool destroyMeshes=true)
Cleans up references to objects that we have created.
void CleanUpSurface(SurfaceObject surface, bool destroyGameObject=true, bool destroyMeshes=true, GameObject objectToPreserve=null, Mesh meshToPreserveA=null, Mesh meshToPreserveB=null)
Clean up the resources associated with the surface.
The SpatialMappingManager class allows applications to use a SurfaceObserver or a stored Spatial Mapp...
SurfaceObject UpdateOrAddSurfaceObject(SurfaceObject toUpdateOrAdd, bool destroyGameObjectIfReplaced=true, bool destroyMeshesIfReplaced=true)
Update the first surface with a matching ID if one exists in SurfaceObjects, otherwise add the surfac...
SurfaceObject RemoveSurfaceIfFound(int surfaceID, bool destroyGameObject=true, bool destroyMeshes=true)
Remove the first surface with the specified ID if one exists in SurfaceObjects.
EventHandler< DataEventArgs< SurfaceObject > > SurfaceRemoved
EventHandler< DataEventArgs< SurfaceObject > > SurfaceAdded
virtual List< MeshRenderer > GetMeshRenderers()
Gets all mesh renderers that have been created.