private async void OnEnable() { await new WaitUntil(() => SpatialAwarenessSystem != null); SpatialAwarenessSystem.Register(gameObject); await new WaitUntil(() => DataProviderAccess != null); await new WaitUntil(() => MeshObserver != null); }
/// <summary> /// Sends the observations using the mesh data contained within the configured 3D model. /// </summary> private void SendMeshObjects() { if (!sendObservations) { return; } if (spatialMeshObject != null) { MeshFilter[] meshFilters = spatialMeshObject.GetComponentsInChildren <MeshFilter>(); for (int i = 0; i < meshFilters.Length; i++) { SpatialAwarenessMeshObject meshObject = SpatialAwarenessMeshObject.Create( meshFilters[i].sharedMesh, MeshPhysicsLayer, $"Spatial Object Mesh {currentMeshId}", currentMeshId, ObservedObjectParent); meshObject.GameObject.transform.localPosition = meshFilters[i].transform.position; meshObject.GameObject.transform.localRotation = meshFilters[i].transform.rotation; ApplyMeshMaterial(meshObject); meshes.Add(currentMeshId, meshObject); meshEventData.Initialize(this, currentMeshId, meshObject); SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded); currentMeshId++; } } sendObservations = false; }
/// <summary> /// Constructor. /// </summary> /// <param name="spatialAwarenessSystem">The <see cref="SpatialAwareness.IMixedRealitySpatialAwarenessSystem"/> to which the observer is providing data.</param> /// <param name="name">The friendly name of the data provider.</param> /// <param name="priority">The registration priority of the data provider.</param> /// <param name="profile">The configuration profile for the data provider.</param> protected BaseSpatialObserver( IMixedRealitySpatialAwarenessSystem spatialAwarenessSystem, string name = null, uint priority = DefaultPriority, BaseMixedRealityProfile profile = null) : base(spatialAwarenessSystem, name, priority, profile) { SpatialAwarenessSystem = spatialAwarenessSystem; SourceId = (SpatialAwarenessSystem != null) ? SpatialAwarenessSystem.GenerateNewSourceId() : 0; SourceName = name; }
/// <summary> /// Removes the <see cref="SpatialAwarenessMeshObject"/> associated with the specified id. /// </summary> /// <param name="id">The id of the mesh to be removed.</param> protected void RemoveMeshObject(int id) { SpatialAwarenessMeshObject mesh; if (meshes.TryGetValue(id, out mesh)) { // Remove the mesh object from the collection. meshes.Remove(id); // Reclaim the mesh object for future use. ReclaimMeshObject(mesh); // Send the mesh removed event SpatialAwarenessSystem?.RaiseMeshRemoved(this, id); } }
/// <summary> /// Removes an observation. /// </summary> private void RemoveMeshObject(int meshId) { if (meshes.TryGetValue(meshId, out SpatialAwarenessMeshObject meshObject)) { // Remove the mesh object from the collection. meshes.Remove(meshId); if (meshObject != null) { SpatialAwarenessMeshObject.Cleanup(meshObject); } // Send the mesh removed event meshEventData.Initialize(this, meshId, null); SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshRemoved); } }
/// <summary> /// Removes the <see cref="SpatialAwarenessMeshObject"/> associated with the specified id. /// </summary> /// <param name="id">The id of the mesh to be removed.</param> protected void RemoveMeshObject(int id) { SpatialAwarenessMeshObject mesh; if (meshes.TryGetValue(id, out mesh)) { // Remove the mesh object from the collection. meshes.Remove(id); // Reclaim the mesh object for future use. ReclaimMeshObject(mesh); // Send the mesh removed event meshEventData.Initialize(this, id, null); SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshRemoved); } }
private void MeshGenerationAction(MeshGenerationResult meshGenerationResult) { if (!IsRunning) { return; } using (MeshGenerationActionPerfMarker.Auto()) { if (outstandingMeshObject == null) { Debug.LogWarning($"MeshGenerationAction called for mesh id {meshGenerationResult.MeshId} while no request was outstanding."); return; } switch (meshGenerationResult.Status) { case MeshGenerationStatus.InvalidMeshId: case MeshGenerationStatus.Canceled: case MeshGenerationStatus.UnknownError: outstandingMeshObject = null; break; case MeshGenerationStatus.Success: // Since there is only one outstanding mesh object, update the id to match // the one received after baking. SpatialAwarenessMeshObject meshObject = outstandingMeshObject; meshObject.Id = meshGenerationResult.MeshId.GetHashCode(); outstandingMeshObject = null; // Apply the appropriate material to the mesh. SpatialAwarenessMeshDisplayOptions displayOption = DisplayOption; if (displayOption != SpatialAwarenessMeshDisplayOptions.None) { meshObject.Renderer.enabled = true; meshObject.Renderer.sharedMaterial = (displayOption == SpatialAwarenessMeshDisplayOptions.Visible) ? VisibleMaterial : OcclusionMaterial; meshObject.Collider.material = PhysicsMaterial; } else { meshObject.Renderer.enabled = false; } // Recalculate the mesh normals if requested. if (RecalculateNormals) { meshObject.Filter.sharedMesh.RecalculateNormals(); } // Add / update the mesh to our collection bool sendUpdatedEvent = false; if (meshes.ContainsKey(meshObject.Id)) { // Reclaim the old mesh object for future use. ReclaimMeshObject(meshes[meshObject.Id]); meshes.Remove(meshObject.Id); sendUpdatedEvent = true; } meshes.Add(meshObject.Id, meshObject); meshObject.GameObject.transform.parent = (ObservedObjectParent.transform != null) ? ObservedObjectParent.transform : null; meshEventData.Initialize(this, meshObject.Id, meshObject); if (sendUpdatedEvent) { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshUpdated); } else { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded); } break; } } }
/// <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(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds) { if (!IsRunning) { return; } if (outstandingMeshObject == null) { return; } if (!outputWritten) { ReclaimMeshObject(outstandingMeshObject); outstandingMeshObject = null; return; } // Since there is only one outstanding mesh object, update the id to match // the one received after baking. SpatialAwarenessMeshObject meshObject = outstandingMeshObject; meshObject.Id = cookedData.id.handle; outstandingMeshObject = null; // Apply the appropriate material to the mesh. SpatialAwarenessMeshDisplayOptions displayOption = DisplayOption; if (displayOption != SpatialAwarenessMeshDisplayOptions.None) { meshObject.Renderer.enabled = true; meshObject.Renderer.sharedMaterial = (displayOption == SpatialAwarenessMeshDisplayOptions.Visible) ? VisibleMaterial : OcclusionMaterial; } else { meshObject.Renderer.enabled = false; } // Recalculate the mesh normals if requested. if (RecalculateNormals) { meshObject.Filter.sharedMesh.RecalculateNormals(); } // Add / update the mesh to our collection bool sendUpdatedEvent = false; if (meshes.ContainsKey(cookedData.id.handle)) { // Reclaim the old mesh object for future use. ReclaimMeshObject(meshes[cookedData.id.handle]); meshes.Remove(cookedData.id.handle); sendUpdatedEvent = true; } meshes.Add(cookedData.id.handle, meshObject); meshObject.GameObject.transform.parent = (ObservedObjectParent.transform != null) ? ObservedObjectParent.transform : null; meshEventData.Initialize(this, cookedData.id.handle, meshObject); if (sendUpdatedEvent) { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshUpdated); } else { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded); } }
private void MeshGenerationAction(MeshGenerationResult meshGenerationResult) { if (!IsRunning) { return; } using (MeshGenerationActionPerfMarker.Auto()) { if (outstandingMeshObject == null) { Debug.LogWarning($"MeshGenerationAction called for mesh id {meshGenerationResult.MeshId} while no request was outstanding."); return; } switch (meshGenerationResult.Status) { case MeshGenerationStatus.InvalidMeshId: case MeshGenerationStatus.Canceled: case MeshGenerationStatus.UnknownError: outstandingMeshObject = null; break; case MeshGenerationStatus.Success: // Since there is only one outstanding mesh object, update the id to match // the one received after baking. SpatialAwarenessMeshObject meshObject = outstandingMeshObject; meshObject.Id = meshGenerationResult.MeshId.GetHashCode(); outstandingMeshObject = null; // Check to see if this is a new or updated mesh. bool isMeshUpdate = meshes.ContainsKey(meshObject.Id); // We presume that if the display option is not occlusion, that we should // default to the visible material. // Note: We check explicitly for a display option of none later in this method. Material material = (DisplayOption == SpatialAwarenessMeshDisplayOptions.Occlusion) ? OcclusionMaterial : VisibleMaterial; // If this is a mesh update, we want to preserve the mesh's previous material. material = isMeshUpdate ? meshes[meshObject.Id].Renderer.sharedMaterial : material; // Apply the appropriate material. meshObject.Renderer.sharedMaterial = material; // Recalculate the mesh normals if requested. if (RecalculateNormals) { meshObject.Filter.sharedMesh.RecalculateNormals(); } // Check to see if the display option is set to none. If so, we disable // the renderer. meshObject.Renderer.enabled = (DisplayOption != SpatialAwarenessMeshDisplayOptions.None); // Set the physics material if (meshObject.Renderer.enabled) { meshObject.Collider.material = PhysicsMaterial; } // Add / update the mesh to our collection if (isMeshUpdate) { // Reclaim the old mesh object for future use. ReclaimMeshObject(meshes[meshObject.Id]); meshes.Remove(meshObject.Id); } meshes.Add(meshObject.Id, meshObject); meshObject.GameObject.transform.parent = (ObservedObjectParent.transform != null) ? ObservedObjectParent.transform : null; meshEventData.Initialize(this, meshObject.Id, meshObject); if (isMeshUpdate) { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshUpdated); } else { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded); } break; } } }
/// <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(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds) { if (!IsRunning) { return; } using (OnDataReadyPerfMarker.Auto()) { if (outstandingMeshObject == null) { return; } if (!outputWritten) { ReclaimMeshObject(outstandingMeshObject); outstandingMeshObject = null; return; } // Since there is only one outstanding mesh object, update the id to match // the one received after baking. SpatialAwarenessMeshObject meshObject = outstandingMeshObject; meshObject.Id = cookedData.id.handle; outstandingMeshObject = null; // Check to see if this is a new or updated mesh. bool isMeshUpdate = meshes.ContainsKey(meshObject.Id); // We presume that if the display option is not occlusion, that we should // default to the visible material. // Note: We check explicitly for a display option of none later in this method. Material material = (DisplayOption == SpatialAwarenessMeshDisplayOptions.Occlusion) ? OcclusionMaterial : VisibleMaterial; // If this is a mesh update, we want to preserve the mesh's previous material. material = isMeshUpdate ? meshes[meshObject.Id].Renderer.sharedMaterial : material; // Apply the appropriate material. meshObject.Renderer.sharedMaterial = material; // Recalculate the mesh normals if requested. if (RecalculateNormals) { meshObject.Filter.sharedMesh.RecalculateNormals(); } // Check to see if the display option is set to none. If so, we disable // the renderer. meshObject.Renderer.enabled = (DisplayOption != SpatialAwarenessMeshDisplayOptions.None); // Set the physics material if (meshObject.Renderer.enabled) { meshObject.Collider.material = PhysicsMaterial; } // Add / update the mesh to our collection if (isMeshUpdate) { // Reclaim the old mesh object for future use. ReclaimMeshObject(meshes[meshObject.Id]); meshes.Remove(meshObject.Id); } meshes.Add(meshObject.Id, meshObject); // Preserve local transform relative to parent. meshObject.GameObject.transform.SetParent(ObservedObjectParent != null ? ObservedObjectParent.transform: null, false); meshEventData.Initialize(this, meshObject.Id, meshObject); if (isMeshUpdate) { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshUpdated); } else { SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded); } } }
private void OnDisable() { SpatialAwarenessSystem?.Unregister(gameObject); }
/// <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(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds) { if (!IsRunning) { return; } if (!outstandingMeshObject.HasValue) { Debug.LogWarning($"OnDataReady called for mesh id {cookedData.id.handle} while no request was outstanding."); return; } if (!outputWritten) { Debug.LogWarning($"OnDataReady reported no data written for mesh id {cookedData.id.handle}"); ReclaimMeshObject(outstandingMeshObject.Value); outstandingMeshObject = null; return; } // Since there is only one outstanding mesh object, update the id to match // the one received after baking. SpatialMeshObject meshObject = outstandingMeshObject.Value; meshObject.Id = cookedData.id.handle; outstandingMeshObject = null; // Apply the appropriate material to the mesh. SpatialMeshDisplayOptions displayOption = SpatialAwarenessSystem.MeshDisplayOption; if (displayOption != SpatialMeshDisplayOptions.None) { meshObject.Renderer.enabled = true; meshObject.Renderer.sharedMaterial = (displayOption == SpatialMeshDisplayOptions.Visible) ? SpatialAwarenessSystem.MeshVisibleMaterial : SpatialAwarenessSystem.MeshOcclusionMaterial; } else { meshObject.Renderer.enabled = false; } // Recalculate the mesh normals if requested. if (SpatialAwarenessSystem.MeshRecalculateNormals) { meshObject.Filter.sharedMesh.RecalculateNormals(); } // Add / update the mesh to our collection bool sendUpdatedEvent = false; if (meshObjects.ContainsKey(cookedData.id.handle)) { // Reclaim the old mesh object for future use. ReclaimMeshObject(meshObjects[cookedData.id.handle]); meshObjects.Remove(cookedData.id.handle); sendUpdatedEvent = true; } meshObjects.Add(cookedData.id.handle, meshObject); if (sendUpdatedEvent) { SpatialAwarenessSystem.RaiseMeshUpdated(cookedData.id.handle, meshObject.GameObject); } else { SpatialAwarenessSystem.RaiseMeshAdded(cookedData.id.handle, meshObject.GameObject); } }
/// <summary> /// Sends SceneObject Added event via <see cref="IMixedRealitySpatialAwarenessObservationHandler{T}"/> /// </summary> /// <param name="sceneObj">The <see cref="SpatialAwarenessSceneObject"/> being created</param> /// <param name="id">the id associated with the <paramref name="sceneObj"/></param> protected virtual void SendSceneObjectAdded(SpatialAwarenessSceneObject sceneObj, Guid id) { // Send the mesh removed event sceneEventData.Initialize(this, id, sceneObj); SpatialAwarenessSystem?.HandleEvent(sceneEventData, OnSceneObjectAdded); }