/// <summary> /// Handles the SurfaceObserver's OnDataReady event. /// </summary> /// <param name="cookedData">Struct containing output data.</param> /// <param name="outputWritten">Set to true if output has been written.</param> /// <param name="elapsedCookTimeSeconds">Seconds between mesh cook request and propagation of this event.</param> private void SurfaceObserver_OnDataReady(UnityEngine.VR.WSA.SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds) { //We have new visuals, so we can disable and cleanup the older surface GameObject surfaceToCleanup; if (pendingCleanup.TryGetValue(cookedData.id.handle, out surfaceToCleanup)) { CleanupSurface(surfaceToCleanup); pendingCleanup.Remove(cookedData.id.handle); } GameObject surface; if (surfaces.TryGetValue(cookedData.id.handle, out surface)) { // Set the draw material for the renderer. MeshRenderer renderer = surface.GetComponent <MeshRenderer>(); renderer.sharedMaterial = SpatialMappingManager.Instance.SurfaceMaterial; renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes; if (SpatialMappingManager.Instance.CastShadows == false) { renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } } surfaceWorkOutstanding = false; UnityEngine.VR.WSA.SurfaceObserver.SurfaceDataReadyDelegate dataReady = DataReady; if (dataReady != null) { dataReady(cookedData, outputWritten, elapsedCookTimeSeconds); } }
private bool IsMatchingSurface(SurfaceObject surfaceObject, UnityEngine.VR.WSA.SurfaceData surfaceData) { return((surfaceObject.ID == surfaceData.id.handle) && (surfaceObject.Filter == surfaceData.outputMesh) && (surfaceObject.Collider == surfaceData.outputCollider) ); }
/// <summary> /// Handles the SurfaceObserver's OnDataReady event. /// </summary> /// <param name="cookedData">Struct containing output data.</param> /// <param name="outputWritten">Set to true if output has been written.</param> /// <param name="elapsedCookTimeSeconds">Seconds between mesh cook request and propagation of this event.</param> private void SurfaceObserver_OnDataReady(UnityEngine.VR.WSA.SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds) { if (outstandingMeshRequest == null) { Debug.LogErrorFormat("Got OnDataReady for surface {0} while no request was outstanding.", cookedData.id.handle ); return; } if (!IsMatchingSurface(outstandingMeshRequest.Value, cookedData)) { Debug.LogErrorFormat("Got mismatched OnDataReady for surface {0} while request for surface {1} was outstanding.", cookedData.id.handle, outstandingMeshRequest.Value.ID ); ReclaimSurface(outstandingMeshRequest.Value); outstandingMeshRequest = null; return; } if (ObserverState != ObserverStates.Running) { Debug.LogFormat("Got OnDataReady for surface {0}, but observer was no longer running.", cookedData.id.handle ); ReclaimSurface(outstandingMeshRequest.Value); outstandingMeshRequest = null; return; } if (!outputWritten) { ReclaimSurface(outstandingMeshRequest.Value); outstandingMeshRequest = null; return; } Debug.Assert(outstandingMeshRequest.Value.Object.activeSelf); outstandingMeshRequest.Value.Renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes; SurfaceObject?replacedSurface = UpdateOrAddSurfaceObject(outstandingMeshRequest.Value, destroyGameObjectIfReplaced: false); outstandingMeshRequest = null; if (replacedSurface != null) { ReclaimSurface(replacedSurface.Value); } }
/// <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> /// Called once per frame. /// </summary> private void Update() { // Only do processing if the observer is running. if (ObserverState == ObserverStates.Running) { // If we don't have mesh creation in flight, but we could schedule mesh creation, do so. if (surfaceWorkOutstanding == false && surfaceWorkQueue.Count > 0) { // Pop the SurfaceData off the queue. A more sophisticated algorithm could prioritize // the queue based on distance to the user or some other metric. UnityEngine.VR.WSA.SurfaceData surfaceData = surfaceWorkQueue.Dequeue(); // If RequestMeshAsync succeeds, then we have successfully scheduled mesh creation. surfaceWorkOutstanding = observer.RequestMeshAsync(surfaceData, SurfaceObserver_OnDataReady); } // If we don't have any other work to do, and enough time has passed since the previous // update request, request updates for the spatial mapping data. else if (surfaceWorkOutstanding == false && (Time.time - updateTime) >= TimeBetweenUpdates) { observer.Update(SurfaceObserver_OnSurfaceChanged); updateTime = Time.time; } } }
/// <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; } } }