/// <summary> /// Handles the SurfaceObserver's OnSurfaceChanged event. /// </summary> /// <param name="id">The identifier assigned to the surface which has changed.</param> /// <param name="changeType">The type of change that occurred on the surface.</param> /// <param name="bounds">The bounds of the surface.</param> /// <param name="updateTime">The date and time at which the change occurred.</param> private void SurfaceObserver_OnSurfaceChanged(UnityEngine.VR.WSA.SurfaceId id, UnityEngine.VR.WSA.SurfaceChange changeType, Bounds bounds, DateTime updateTime) { // Verify that the client of the Surface Observer is expecting updates. if (ObserverState != ObserverStates.Running) { return; } switch (changeType) { case UnityEngine.VR.WSA.SurfaceChange.Added: case UnityEngine.VR.WSA.SurfaceChange.Updated: surfaceWorkQueue.Enqueue(id); break; case UnityEngine.VR.WSA.SurfaceChange.Removed: SurfaceObject?removedSurface = RemoveSurfaceIfFound(id.handle, destroyGameObject: false); if (removedSurface != null) { ReclaimSurface(removedSurface.Value); } break; default: Debug.LogErrorFormat("Unexpected {0} value: {1}.", changeType.GetType(), changeType); break; } }
/// <summary> /// Calls GetMeshAsync to update the SurfaceData and re-activate the surface object when ready. /// </summary> /// <param name="id">Identifier of the SurfaceData object to update.</param> /// <param name="surface">The SurfaceData object to update.</param> private void QueueSurfaceDataRequest(UnityEngine.VR.WSA.SurfaceId id, GameObject surface) { UnityEngine.VR.WSA.SurfaceData surfaceData = new UnityEngine.VR.WSA.SurfaceData(id, surface.GetComponent <MeshFilter>(), surface.GetComponent <UnityEngine.VR.WSA.WorldAnchor>(), surface.GetComponent <MeshCollider>(), TrianglesPerCubicMeter, true); surfaceWorkQueue.Enqueue(surfaceData); }
/// <summary> /// Handles the SurfaceObserver's OnSurfaceChanged event. /// </summary> /// <param name="id">The identifier assigned to the surface which has changed.</param> /// <param name="changeType">The type of change that occurred on the surface.</param> /// <param name="bounds">The bounds of the surface.</param> /// <param name="updateTime">The date and time at which the change occurred.</param> private void SurfaceObserver_OnSurfaceChanged(UnityEngine.VR.WSA.SurfaceId id, UnityEngine.VR.WSA.SurfaceChange changeType, Bounds bounds, System.DateTime updateTime) { // Verify that the client of the Surface Observer is expecting updates. if (ObserverState != ObserverStates.Running) { return; } GameObject surface; switch (changeType) { // Adding and updating are nearly identical. The only difference is if a new gameobject to contain // the surface needs to be created. case UnityEngine.VR.WSA.SurfaceChange.Added: case UnityEngine.VR.WSA.SurfaceChange.Updated: // Check to see if the surface is known to the observer. // If so, we want to add it for cleanup after we get new meshes // We do this because Unity doesn't properly cleanup baked collision data if (surfaces.TryGetValue(id.handle, out surface)) { pendingCleanup.Add(id.handle, surface); surfaces.Remove(id.handle); } // Get an available surface object ready to be used surface = GetSurfaceObject(id.handle, transform); // Add the surface to our dictionary of known surfaces so // we can interact with it later. surfaces.Add(id.handle, surface); // Add the request to create the mesh for this surface to our work queue. QueueSurfaceDataRequest(id, surface); break; case UnityEngine.VR.WSA.SurfaceChange.Removed: // Always process surface removal events. // This code can be made more thread safe if (surfaces.TryGetValue(id.handle, out surface)) { surfaces.Remove(id.handle); CleanupSurface(surface); RemoveSurfaceObject(surface, false); } break; } // Event if (SurfaceChanged != null) { SurfaceChanged(id, changeType, bounds, updateTime); } }
/// <summary> /// Called once per frame. /// </summary> private void Update() { if ((ObserverState == ObserverStates.Running) && (outstandingMeshRequest == null)) { if (surfaceWorkQueue.Count > 0) { // We're using a simple first-in-first-out rule for requesting meshes, but a more sophisticated algorithm could prioritize // the queue based on distance to the user or some other metric. UnityEngine.VR.WSA.SurfaceId surfaceID = surfaceWorkQueue.Dequeue(); string surfaceName = ("Surface-" + surfaceID.handle); SurfaceObject newSurface; UnityEngine.VR.WSA.WorldAnchor worldAnchor; if (spareSurfaceObject == null) { newSurface = CreateSurfaceObject( mesh: null, objectName: surfaceName, parentObject: transform, meshID: surfaceID.handle, drawVisualMeshesOverride: false ); worldAnchor = newSurface.Object.AddComponent <UnityEngine.VR.WSA.WorldAnchor>(); } else { newSurface = spareSurfaceObject.Value; spareSurfaceObject = null; Debug.Assert(!newSurface.Object.activeSelf); newSurface.Object.SetActive(true); Debug.Assert(newSurface.Filter.sharedMesh == null); Debug.Assert(newSurface.Collider.sharedMesh == null); newSurface.Object.name = surfaceName; Debug.Assert(newSurface.Object.transform.parent == transform); newSurface.ID = surfaceID.handle; newSurface.Renderer.enabled = false; worldAnchor = newSurface.Object.GetComponent <UnityEngine.VR.WSA.WorldAnchor>(); Debug.Assert(worldAnchor != null); } var surfaceData = new UnityEngine.VR.WSA.SurfaceData( surfaceID, newSurface.Filter, worldAnchor, newSurface.Collider, TrianglesPerCubicMeter, _bakeCollider: true ); if (observer.RequestMeshAsync(surfaceData, SurfaceObserver_OnDataReady)) { outstandingMeshRequest = newSurface; } else { Debug.LogErrorFormat("Mesh request for failed. Is {0} a valid Surface ID?", surfaceID.handle); Debug.Assert(outstandingMeshRequest == null); ReclaimSurface(newSurface); } } else if ((Time.unscaledTime - updateTime) >= TimeBetweenUpdates) { observer.Update(SurfaceObserver_OnSurfaceChanged); updateTime = Time.unscaledTime; } } }