/// <summary> /// Get the surface with the highest priority for retrieving the mesh. Surfaces /// without meshes are prioritized before those with outdated ones, and older /// ones are prioritized before newer ones. /// </summary> /// <returns></returns> private ISpatialSurface GetHighestPrioritySurface() { ISpatialSurface highestPrioritySurface = null; foreach (KeyValuePair <int, ISpatialSurface> surface in _surfaceEntries) { // Only consider surfaces with out of date/without meshes if (surface.Value.MeshStatus != SurfaceMeshStatuses.UP_TO_DATE) { if (highestPrioritySurface == null) { highestPrioritySurface = surface.Value; } else { // Missing meshes before outdated meshes if (surface.Value.MeshStatus < highestPrioritySurface.MeshStatus) { highestPrioritySurface = surface.Value; } // Older meshes first else if (surface.Value.UpdateTime < highestPrioritySurface.UpdateTime) { highestPrioritySurface = surface.Value; } } } } return(highestPrioritySurface); }
/// <summary> /// Checks if the surface observer needs to be updated, if a new mesh request should be started, /// finds the surface with highest priority, and sends a new request for a mesh /// </summary> private void Update() { if (_doUpdates) { // Updating the surface observer is a very expensive procedure, so only do it at the specified intervals if (Time.realtimeSinceStartup > _previousUpdate + _updateInterval) { UpdateBoundingVolume(); try { _surfaceObserver.Update(SurfaceChangedHandler); } catch { // Bad callbacks can throw errors Debug.LogError("SpatialMapper Error: Unexpected failure when updating the surface observer!"); } _previousUpdate = Time.realtimeSinceStartup; } // If there is no current mesh request, start a new one if (!_meshRequestInProgress) { ISpatialSurface highestPrioritySurface = GetHighestPrioritySurface(); if (highestPrioritySurface != null) { SurfaceData sd; sd.id.handle = highestPrioritySurface.Id; sd.outputMesh = highestPrioritySurface.Mesh; sd.outputCollider = highestPrioritySurface.Collider; sd.outputAnchor = highestPrioritySurface.Anchor; sd.trianglesPerCubicMeter = _trianglesPerCubicMeter; sd.bakeCollider = sd.outputCollider != null; try { if (_surfaceObserver.RequestMeshAsync(sd, SurfaceDataReadyHandler)) { _meshRequestInProgress = true; } else { Debug.LogErrorFormat("SpatialMapper Error: Mesh request for {0} failed. Check that {0} is a valid Surface ID.", sd.id); } } catch { // Failure can happen if the data structure is filled out wrong Debug.LogErrorFormat("SpatialMapper Error: Mesh request for {0} failed unexpectedly.", sd.id); } } } } }
/// <summary> /// This method handles observed changes to surfaces (added, updated, or removed). /// These changes have their source in the update loop where the surface observer /// is updated. /// </summary> /// <param name="id">The unique id of the surface</param> /// <param name="changeType">Says if the surface has been added, updated, or removed</param> /// <param name="bounds">The axis aligned bounding box containing the surface</param> /// <param name="updateTime">Time of the update</param> private void SurfaceChangedHandler(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime) { ISpatialSurface surface = null; switch (changeType) { case SurfaceChange.Added: case SurfaceChange.Updated: if (_surfaceEntries.TryGetValue(id.handle, out surface)) { if (surface.MeshStatus == SurfaceMeshStatuses.UP_TO_DATE) { surface.MeshStatus = SurfaceMeshStatuses.OUTDATED; surface.UpdateTime = updateTime; } } else { surface = _surfaceEntryFactory.Create(updateTime, id.handle, _castShadows, _recieveShadows, _meshMaterial, _addColliders, _physicMaterial); surface.Instance.transform.SetParent(_meshParent != null ? _meshParent : transform, false); _surfaceEntries[id.handle] = surface; } break; case SurfaceChange.Removed: if (_surfaceEntries.TryGetValue(id.handle, out surface)) { _surfaceEntries.Remove(id.handle); Mesh mesh = surface.Mesh.mesh; if (mesh) { Destroy(mesh); } Destroy(surface.Instance); } break; default: break; } }