AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SpatialUnderstanding.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 UnityEngine;
7 
8 namespace HoloToolkit.Unity
9 {
14  [RequireComponent(typeof(SpatialUnderstandingSourceMesh))]
15  [RequireComponent(typeof(SpatialUnderstandingCustomMesh))]
16  public class SpatialUnderstanding : Singleton<SpatialUnderstanding>
17  {
18  // Consts
19  public const float ScanSearchDistance = 8.0f;
20 
21  // Enums
22  public enum ScanStates
23  {
24  None,
25  ReadyToScan,
26  Scanning,
27  Finishing,
28  Done
29  }
30 
31  // Config
32  [Tooltip("If set to false, scanning will only begin after RequestBeginScanning is called")]
33  public bool AutoBeginScanning = true;
34  [Tooltip("Update period used during the scanning process (typically faster than after scanning is completed)")]
35  public float UpdatePeriod_DuringScanning = 1.0f;
36  [Tooltip("Update period used after the scanning process is completed")]
37  public float UpdatePeriod_AfterScanning = 4.0f;
38 
39  // Properties
43  public bool AllowSpatialUnderstanding
44  {
45  get
46  {
47  return true;
48  }
49  }
50 
54  public SpatialUnderstandingDll UnderstandingDLL { get; private set; }
58  public SpatialUnderstandingSourceMesh UnderstandingSourceMesh { get; private set; }
62  public SpatialUnderstandingCustomMesh UnderstandingCustomMesh { get; private set; }
66  public ScanStates ScanState
67  {
68  get
69  {
70  return scanState;
71  }
72  private set
73  {
74  scanState = value;
75  if (ScanStateChanged != null)
76  {
77  ScanStateChanged();
78  }
79 
80  // Update scan period, based on state
81  SpatialMappingManager.Instance.GetComponent<SpatialMappingObserver>().TimeBetweenUpdates = (scanState == ScanStates.Done) ? UpdatePeriod_AfterScanning : UpdatePeriod_DuringScanning;
82  }
83  }
88  public bool ScanStatsReportStillWorking
89  {
90  get
91  {
92  if (AllowSpatialUnderstanding)
93  {
94  SpatialUnderstandingDll.Imports.PlayspaceStats stats = UnderstandingDLL.GetStaticPlayspaceStats();
95  return (stats.IsWorkingOnStats != 0);
96  }
97  return false;
98  }
99  }
100 
101  public delegate void OnScanDoneDelegate();
102 
103  // Events
107  public event OnScanDoneDelegate OnScanDone;
108 
112  public event Action ScanStateChanged;
113 
114  // Privates
115  private ScanStates scanState;
116 
117  private float timeSinceLastUpdate = 0.0f;
118 
119  // Functions
120  protected override void Awake()
121  {
122  base.Awake();
123 
124  // Cache references to required component
125  UnderstandingDLL = new SpatialUnderstandingDll();
126  UnderstandingSourceMesh = GetComponent<SpatialUnderstandingSourceMesh>();
127  UnderstandingCustomMesh = GetComponent<SpatialUnderstandingCustomMesh>();
128  }
129 
130  private void Start()
131  {
132  // Initialize the DLL
133  if (AllowSpatialUnderstanding)
134  {
136  }
137  }
138 
139  private void Update()
140  {
141  if (!AllowSpatialUnderstanding)
142  {
143  return;
144  }
145 
146  // Only update every few frames, and only if we aren't pulling in a mesh
147  // already.
148  timeSinceLastUpdate += Time.deltaTime;
149  if ((!UnderstandingCustomMesh.IsImportActive) &&
150  (Time.frameCount % 3 == 0))
151  {
152  // Real-Time scan
153  Update_Scan(timeSinceLastUpdate);
154  timeSinceLastUpdate = 0;
155  }
156  }
157 
158  protected override void OnDestroy()
159  {
160  // Term the DLL
161  if (AllowSpatialUnderstanding)
162  {
164  }
165 
166  base.OnDestroy();
167  }
168 
173  public void RequestBeginScanning()
174  {
175  if (ScanState == ScanStates.None)
176  {
177  ScanState = ScanStates.ReadyToScan;
178  }
179  }
180 
187  public void RequestFinishScan()
188  {
189  if (AllowSpatialUnderstanding)
190  {
192  ScanState = ScanStates.Finishing;
193  }
194  }
195 
201  private void Update_Scan(float deltaTime)
202  {
203  // If we auto-start scanning, do it now
204  if (AutoBeginScanning &&
205  (ScanState == ScanStates.None))
206  {
207  RequestBeginScanning();
208  }
209 
210  // Update the scan
211  bool scanDone = false;
212  if (((ScanState == ScanStates.ReadyToScan) ||
213  (ScanState == ScanStates.Scanning) ||
214  (ScanState == ScanStates.Finishing)) &&
215  (AllowSpatialUnderstanding))
216  {
217  // Camera
218  Transform cameraTransform = CameraCache.Main.transform;
219  Vector3 camPos = cameraTransform.position;
220  Vector3 camFwd = cameraTransform.forward;
221  Vector3 camUp = cameraTransform.up;
222 
223  // If not yet initialized, do that now
224  if (ScanState == ScanStates.ReadyToScan)
225  {
227  camPos.x, camPos.y, camPos.z,
228  camFwd.x, camFwd.y, camFwd.z,
229  camUp.x, camUp.y, camUp.z,
230  ScanSearchDistance, ScanSearchDistance);
231  ScanState = ScanStates.Scanning;
232  }
233 
234  // Update
235  int meshCount;
236  IntPtr meshList;
237  if (UnderstandingSourceMesh.GetInputMeshList(out meshCount, out meshList))
238  {
239  var stopWatch = System.Diagnostics.Stopwatch.StartNew();
240 
242  meshCount, meshList,
243  camPos.x, camPos.y, camPos.z,
244  camFwd.x, camFwd.y, camFwd.z,
245  camUp.x, camUp.y, camUp.z,
246  deltaTime) == 1;
247 
248  stopWatch.Stop();
249 
250  if (stopWatch.Elapsed.TotalMilliseconds > (1000.0 / 30.0))
251  {
252  Debug.LogWarningFormat("SpatialUnderstandingDll.Imports.GeneratePlayspace_UpdateScan took {0,9:N2} ms", stopWatch.Elapsed.TotalMilliseconds);
253  }
254  }
255  }
256 
257  // If it's done, finish up
258  if ((ScanState == ScanStates.Finishing) &&
259  (scanDone) &&
260  (!UnderstandingCustomMesh.IsImportActive) &&
261  (UnderstandingCustomMesh != null))
262  {
263  // Final mesh import
264  StartCoroutine(UnderstandingCustomMesh.Import_UnderstandingMesh());
265 
266  // Mark it
267  ScanState = ScanStates.Done;
268  if (OnScanDone != null) OnScanDone.Invoke();
269  }
270  }
271  }
272 }
void RequestBeginScanning()
Call to request that scanning should begin. If AutoBeginScanning is false, this function should be us...
static void GeneratePlayspace_RequestFinish()
Request scanning that the scanning phase be ended and the playspace finalized. This should be called ...
static int SpatialUnderstanding_Init()
Initialize the spatial understanding DLL. Function must be called before any other DLL function...
override void Awake()
Base Awake method that sets the Singleton&#39;s unique instance. Called by Unity when initializing a Mono...
The SpatialMappingObserver class encapsulates the SurfaceObserver into an easy to use object that han...
Encapsulates the primary DLL functions, including marshalling helper functions. The DLL functions are...
override void OnDestroy()
Base OnDestroy method that destroys the Singleton&#39;s unique instance. Called by Unity when destroying ...
static void GeneratePlayspace_InitScan([In] float camPos_X, [In] float camPos_Y, [In] float camPos_Z, [In] float camFwd_X, [In] float camFwd_Y, [In] float camFwd_Z, [In] float camUp_X, [In] float camUp_Y, [In] float camUp_Z, [In] float searchDst, [In] float optimalSize)
Initialize the scanning process.
static int GeneratePlayspace_UpdateScan([In] int meshCount, [In] IntPtr meshes, [In] float camPos_X, [In] float camPos_Y, [In] float camPos_Z, [In] float camFwd_X, [In] float camFwd_Y, [In] float camFwd_Z, [In] float camUp_X, [In] float camUp_Y, [In] float camUp_Z, [In] float deltaTime)
Update the playspace scanning. Should be called once per frame during scanning.
OnScanDoneDelegate OnScanDone
Event indicating that the scan is done
static void SpatialUnderstanding_Term()
Terminate the spatial understanding DLL.
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
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
Action ScanStateChanged
Event indicating that the scan state has changed
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
The SpatialMappingManager class allows applications to use a SurfaceObserver or a stored Spatial Mapp...
Handles the custom meshes generated by the understanding DLL. The meshes are generated during the sca...
Provides the input meshes to the spatial understanding DLL. The component relies on the spatial mappi...
Playspace statistics for querying scanning progress
The SpatialUnderstanding class controls the state and flow of the scanning process used in the unders...
void RequestFinishScan()
Call to request that the scanning progress be finishing. The application must do this to finalize the...
Singleton behaviour class, used for components that should only have one instance.
Definition: Singleton.cs:14