From 5181b20078712159eb861449d69c764124f10c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Fejzagi=C4=87?= Date: Wed, 15 May 2024 17:30:15 +0200 Subject: [PATCH] Transfer existng code --- .../SpatialAwarenessSystemProfile.asset | 19 + .../SpatialAwarenessSystemProfile.asset.meta | 8 + .../Profiles/SpatialMeshObserverProfile.asset | 27 ++ .../SpatialMeshObserverProfile.asset.meta | 8 + ...ssPlatformServiceConfigurationsProfile.txt | 1 - ...BaseSpatialMeshObserverProfileInspector.cs | 107 ++++++ ...patialMeshObserverProfileInspector.cs.meta | 11 + Editor/BaseSpatialObserverProfileInspector.cs | 60 +++ ...aseSpatialObserverProfileInspector.cs.meta | 11 + Editor/BaseSurfaceObserverProfileInspector.cs | 72 ++++ ...aseSurfaceObserverProfileInspector.cs.meta | 11 + ...lityToolkit.SpatialAwareness.Editor.asmdef | 3 +- ...arenessEditorActiveProfileChangeHandler.cs | 37 ++ ...ssEditorActiveProfileChangeHandler.cs.meta | 11 + ...SpatialAwarenessPackageModulesInstaller.cs | 85 ++--- ...patialAwarenessSserviceProfileInspector.cs | 53 +++ ...lAwarenessSserviceProfileInspector.cs.meta | 11 + Runtime/Definitions.meta | 8 + .../SpatialAwarenessMeshLevelOfDetail.cs | 32 ++ .../SpatialAwarenessMeshLevelOfDetail.cs.meta | 11 + .../SpatialAwarenessServiceProfile.cs | 60 +++ .../SpatialAwarenessServiceProfile.cs.meta | 11 + .../SpatialAwarenessSurfaceTypes.cs | 41 +++ .../SpatialAwarenessSurfaceTypes.cs.meta | 11 + .../Definitions/SpatialMeshDisplayOptions.cs | 31 ++ .../SpatialMeshDisplayOptions.cs.meta | 11 + Runtime/Definitions/SpatialMeshObject.cs | 85 +++++ Runtime/Definitions/SpatialMeshObject.cs.meta | 11 + Runtime/Definitions/SpatialObserverStatus.cs | 26 ++ .../Definitions/SpatialObserverStatus.cs.meta | 11 + Runtime/Definitions/SpatialObservers.meta | 8 + .../BaseSpatialMeshObserverProfile.cs | 70 ++++ .../BaseSpatialMeshObserverProfile.cs.meta | 11 + .../BaseSpatialObserverProfile.cs | 64 ++++ .../BaseSpatialObserverProfile.cs.meta | 11 + .../BaseSurfaceObserverProfile.cs | 96 +++++ .../BaseSurfaceObserverProfile.cs.meta | 11 + Runtime/ISpatialAwarenessService.cs | 158 ++++++++ Runtime/ISpatialAwarenessService.cs.meta | 11 + Runtime/Interfaces.meta | 8 + Runtime/Interfaces/Handlers.meta | 8 + .../Handlers/ISpatialAwarenessMeshHandler.cs | 31 ++ .../ISpatialAwarenessMeshHandler.cs.meta | 11 + .../ISpatialAwarenessSurfaceFindingHandler.cs | 32 ++ ...tialAwarenessSurfaceFindingHandler.cs.meta | 11 + Runtime/Interfaces/SpatialObservers.meta | 8 + .../ISpatialAwarenessServiceModule.cs | 47 +++ .../ISpatialAwarenessServiceModule.cs.meta | 11 + .../SpatialObservers/ISpatialMeshObserver.cs | 96 +++++ .../ISpatialMeshObserver.cs.meta | 11 + .../ISpatialSurfaceObserver.cs | 69 ++++ .../ISpatialSurfaceObserver.cs.meta | 11 + Runtime/Modules.meta | 8 + Runtime/Modules/BaseSpatialMeshObserver.cs | 324 +++++++++++++++++ .../Modules/BaseSpatialMeshObserver.cs.meta | 11 + .../BaseSpatialObserverServiceModule.cs | 168 +++++++++ .../BaseSpatialObserverServiceModule.cs.meta | 11 + Runtime/Modules/BaseSpatialSurfaceObserver.cs | 79 ++++ .../BaseSpatialSurfaceObserver.cs.meta | 11 + Runtime/SpatialAwarenessEventData.cs | 45 +++ Runtime/SpatialAwarenessEventData.cs.meta | 11 + Runtime/SpatialAwarenessService.cs | 344 ++++++++++++++++++ Runtime/SpatialAwarenessService.cs.meta | 11 + 63 files changed, 2651 insertions(+), 50 deletions(-) create mode 100644 Assets~/Profiles/SpatialAwarenessSystemProfile.asset create mode 100644 Assets~/Profiles/SpatialAwarenessSystemProfile.asset.meta create mode 100644 Assets~/Profiles/SpatialMeshObserverProfile.asset create mode 100644 Assets~/Profiles/SpatialMeshObserverProfile.asset.meta delete mode 100644 Assets~/Profiles/spatial_awarenessPlatformServiceConfigurationsProfile.txt create mode 100644 Editor/BaseSpatialMeshObserverProfileInspector.cs create mode 100644 Editor/BaseSpatialMeshObserverProfileInspector.cs.meta create mode 100644 Editor/BaseSpatialObserverProfileInspector.cs create mode 100644 Editor/BaseSpatialObserverProfileInspector.cs.meta create mode 100644 Editor/BaseSurfaceObserverProfileInspector.cs create mode 100644 Editor/BaseSurfaceObserverProfileInspector.cs.meta create mode 100644 Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs create mode 100644 Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs.meta create mode 100644 Editor/SpatialAwarenessSserviceProfileInspector.cs create mode 100644 Editor/SpatialAwarenessSserviceProfileInspector.cs.meta create mode 100644 Runtime/Definitions.meta create mode 100644 Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs create mode 100644 Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs.meta create mode 100644 Runtime/Definitions/SpatialAwarenessServiceProfile.cs create mode 100644 Runtime/Definitions/SpatialAwarenessServiceProfile.cs.meta create mode 100644 Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs create mode 100644 Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs.meta create mode 100644 Runtime/Definitions/SpatialMeshDisplayOptions.cs create mode 100644 Runtime/Definitions/SpatialMeshDisplayOptions.cs.meta create mode 100644 Runtime/Definitions/SpatialMeshObject.cs create mode 100644 Runtime/Definitions/SpatialMeshObject.cs.meta create mode 100644 Runtime/Definitions/SpatialObserverStatus.cs create mode 100644 Runtime/Definitions/SpatialObserverStatus.cs.meta create mode 100644 Runtime/Definitions/SpatialObservers.meta create mode 100644 Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs create mode 100644 Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs.meta create mode 100644 Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs create mode 100644 Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs.meta create mode 100644 Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs create mode 100644 Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs.meta create mode 100644 Runtime/ISpatialAwarenessService.cs create mode 100644 Runtime/ISpatialAwarenessService.cs.meta create mode 100644 Runtime/Interfaces.meta create mode 100644 Runtime/Interfaces/Handlers.meta create mode 100644 Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs create mode 100644 Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs.meta create mode 100644 Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs create mode 100644 Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs.meta create mode 100644 Runtime/Interfaces/SpatialObservers.meta create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs.meta create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs.meta create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs create mode 100644 Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs.meta create mode 100644 Runtime/Modules.meta create mode 100644 Runtime/Modules/BaseSpatialMeshObserver.cs create mode 100644 Runtime/Modules/BaseSpatialMeshObserver.cs.meta create mode 100644 Runtime/Modules/BaseSpatialObserverServiceModule.cs create mode 100644 Runtime/Modules/BaseSpatialObserverServiceModule.cs.meta create mode 100644 Runtime/Modules/BaseSpatialSurfaceObserver.cs create mode 100644 Runtime/Modules/BaseSpatialSurfaceObserver.cs.meta create mode 100644 Runtime/SpatialAwarenessEventData.cs create mode 100644 Runtime/SpatialAwarenessEventData.cs.meta create mode 100644 Runtime/SpatialAwarenessService.cs create mode 100644 Runtime/SpatialAwarenessService.cs.meta diff --git a/Assets~/Profiles/SpatialAwarenessSystemProfile.asset b/Assets~/Profiles/SpatialAwarenessSystemProfile.asset new file mode 100644 index 0000000..07003d3 --- /dev/null +++ b/Assets~/Profiles/SpatialAwarenessSystemProfile.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 80a1ad34855542cbbd15a6a6dde2e935, type: 3} + m_Name: MixedRealitySpatialAwarenessSystemProfile + m_EditorClassIdentifier: + configurations: [] + meshDisplayOption: 0 + globalMeshObserverProfile: {fileID: 11400000, guid: 6cbcb6266beaa724780d064525cf2896, + type: 2} + globalSurfaceObserverProfile: {fileID: 0} diff --git a/Assets~/Profiles/SpatialAwarenessSystemProfile.asset.meta b/Assets~/Profiles/SpatialAwarenessSystemProfile.asset.meta new file mode 100644 index 0000000..04a5a97 --- /dev/null +++ b/Assets~/Profiles/SpatialAwarenessSystemProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41ce31a4954544c58d16f6b3c4c88f4b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets~/Profiles/SpatialMeshObserverProfile.asset b/Assets~/Profiles/SpatialMeshObserverProfile.asset new file mode 100644 index 0000000..7f3aeb4 --- /dev/null +++ b/Assets~/Profiles/SpatialMeshObserverProfile.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34e54930903b41a9bdcbe94df832101b, type: 3} + m_Name: MixedRealitySpatialMeshObserverProfile + m_EditorClassIdentifier: + startupBehavior: 0 + observationExtents: {x: 3, y: 3, z: 3} + isStationaryObserver: 0 + updateInterval: 0.25 + physicsLayer: 31 + meshLevelOfDetail: 1 + meshTrianglesPerCubicMeter: 0 + meshRecalculateNormals: 1 + meshVisibleMaterial: {fileID: 2100000, guid: 58998db165b741089929938ea4d1b249, type: 2} + meshOcclusionMaterial: {fileID: 2100000, guid: 0062b17981f34cf18ad1f9060db0cb2b, + type: 2} + additionalComponents: [] + meshObjectPrefab: {fileID: 0} diff --git a/Assets~/Profiles/SpatialMeshObserverProfile.asset.meta b/Assets~/Profiles/SpatialMeshObserverProfile.asset.meta new file mode 100644 index 0000000..368834b --- /dev/null +++ b/Assets~/Profiles/SpatialMeshObserverProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6cbcb6266beaa724780d064525cf2896 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets~/Profiles/spatial_awarenessPlatformServiceConfigurationsProfile.txt b/Assets~/Profiles/spatial_awarenessPlatformServiceConfigurationsProfile.txt deleted file mode 100644 index 10b2f57..0000000 --- a/Assets~/Profiles/spatial_awarenessPlatformServiceConfigurationsProfile.txt +++ /dev/null @@ -1 +0,0 @@ -PlatformServiceConfigurationsProfile goes here \ No newline at end of file diff --git a/Editor/BaseSpatialMeshObserverProfileInspector.cs b/Editor/BaseSpatialMeshObserverProfileInspector.cs new file mode 100644 index 0000000..c711979 --- /dev/null +++ b/Editor/BaseSpatialMeshObserverProfileInspector.cs @@ -0,0 +1,107 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Editor.PropertyDrawers; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.Editor; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Editor +{ + [CustomEditor(typeof(BaseSpatialMeshObserverProfile), true, isFallback = true)] + public class BaseSpatialMeshObserverProfileInspector : BaseSpatialObserverProfileInspector + { + private SerializedProperty meshLevelOfDetail; + private SerializedProperty meshRecalculateNormals; + private SerializedProperty meshVisibleMaterial; + private SerializedProperty meshOcclusionMaterial; + private SerializedProperty additionalComponents; + private SerializedProperty meshObjectPrefab; + + private ReorderableList additionalComponentsList; + private int currentlySelectedConfigurationOption; + + private readonly GUIContent spatialMeshSettingsFoldoutHeader = new GUIContent("Spatial Mesh Settings"); + + /// + protected override void OnEnable() + { + base.OnEnable(); + + meshLevelOfDetail = serializedObject.FindProperty(nameof(meshLevelOfDetail)); + meshRecalculateNormals = serializedObject.FindProperty(nameof(meshRecalculateNormals)); + meshVisibleMaterial = serializedObject.FindProperty(nameof(meshVisibleMaterial)); + meshOcclusionMaterial = serializedObject.FindProperty(nameof(meshOcclusionMaterial)); + additionalComponents = serializedObject.FindProperty(nameof(additionalComponents)); + meshObjectPrefab = serializedObject.FindProperty(nameof(meshObjectPrefab)); + + additionalComponentsList = new ReorderableList(serializedObject, additionalComponents, true, false, true, true) + { + elementHeight = EditorGUIUtility.singleLineHeight * 1.2f + }; + + additionalComponentsList.drawHeaderCallback += rect => + { + EditorGUI.LabelField(rect, new GUIContent(additionalComponents.displayName, additionalComponents.tooltip)); + }; + additionalComponentsList.drawElementCallback += DrawConfigurationOptionElement; + additionalComponentsList.onAddCallback += OnConfigurationOptionAdded; + additionalComponentsList.onRemoveCallback += OnConfigurationOptionRemoved; + } + + private void DrawConfigurationOptionElement(Rect rect, int index, bool isActive, bool isFocused) + { + if (isFocused) + { + currentlySelectedConfigurationOption = index; + } + + var componentItem = additionalComponents.GetArrayElementAtIndex(index); + + TypeReferencePropertyDrawer.FilterConstraintOverride = type => !type.IsAbstract && typeof(Component).IsAssignableFrom(type); + EditorGUI.PropertyField(rect, componentItem, GUIContent.none); + } + + private void OnConfigurationOptionAdded(ReorderableList list) + { + additionalComponents.arraySize += 1; + var index = additionalComponents.arraySize - 1; + additionalComponents.GetArrayElementAtIndex(index).FindPropertyRelative("reference").stringValue = string.Empty; + } + + private void OnConfigurationOptionRemoved(ReorderableList list) + { + if (currentlySelectedConfigurationOption >= 0) + { + additionalComponents.DeleteArrayElementAtIndex(currentlySelectedConfigurationOption); + } + } + + /// + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + if (meshLevelOfDetail.FoldoutWithBoldLabelPropertyField(spatialMeshSettingsFoldoutHeader)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(meshRecalculateNormals); + EditorGUILayout.PropertyField(meshVisibleMaterial); + EditorGUILayout.PropertyField(meshOcclusionMaterial); + EditorGUILayout.HelpBox("Additional Components to add to the Spatial Mesh Observer\n\nNote: MeshFilter, MeshRenderer, and MeshCollider are already added automatically as they're required components for a mesh object.", MessageType.Info); + additionalComponentsList.DoLayoutList(); + EditorGUILayout.PropertyField(meshObjectPrefab); + EditorGUILayout.HelpBox("The mesh object is procedurally generated, but you can also use an empty prefab object as well with predefined components and data.", MessageType.Info); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Editor/BaseSpatialMeshObserverProfileInspector.cs.meta b/Editor/BaseSpatialMeshObserverProfileInspector.cs.meta new file mode 100644 index 0000000..454944e --- /dev/null +++ b/Editor/BaseSpatialMeshObserverProfileInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b60d1a1c362145c4be48c5bb9f8459f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 6e2e9d716bbb4d8382bd53f11996b90e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BaseSpatialObserverProfileInspector.cs b/Editor/BaseSpatialObserverProfileInspector.cs new file mode 100644 index 0000000..e5803d7 --- /dev/null +++ b/Editor/BaseSpatialObserverProfileInspector.cs @@ -0,0 +1,60 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Editor.Profiles; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.Editor; +using UnityEditor; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Editor +{ + [CustomEditor(typeof(BaseSpatialObserverProfile), true, isFallback = true)] + public abstract class BaseSpatialObserverProfileInspector : ServiceProfileInspector + { + private SerializedProperty startupBehavior; + private SerializedProperty observationExtents; + private SerializedProperty isStationaryObserver; + private SerializedProperty updateInterval; + private SerializedProperty physicsLayer; + + private readonly GUIContent generalSettingsFoldoutHeader = new GUIContent("General Settings"); + + /// + protected override void OnEnable() + { + base.OnEnable(); + + startupBehavior = serializedObject.FindProperty(nameof(startupBehavior)); + startupBehavior.isExpanded = true; + observationExtents = serializedObject.FindProperty(nameof(observationExtents)); + isStationaryObserver = serializedObject.FindProperty(nameof(isStationaryObserver)); + updateInterval = serializedObject.FindProperty(nameof(updateInterval)); + physicsLayer = serializedObject.FindProperty(nameof(physicsLayer)); + } + + /// + protected override void RenderConfigurationOptions(bool forceExpanded = false) + { + RenderHeader("The Spatial Awareness Observer service module supplies the Spatial Awareness System with all the data it needs to understand the world around you."); + + serializedObject.Update(); + + if (startupBehavior.FoldoutWithBoldLabelPropertyField(generalSettingsFoldoutHeader)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(observationExtents); + EditorGUILayout.PropertyField(isStationaryObserver); + EditorGUILayout.PropertyField(updateInterval); + EditorGUILayout.PropertyField(physicsLayer); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + + DrawServiceModulePropertyDrawer(); + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Editor/BaseSpatialObserverProfileInspector.cs.meta b/Editor/BaseSpatialObserverProfileInspector.cs.meta new file mode 100644 index 0000000..8582ced --- /dev/null +++ b/Editor/BaseSpatialObserverProfileInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1bdd90a3c2a4f40a1643acae7338010 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 6e2e9d716bbb4d8382bd53f11996b90e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BaseSurfaceObserverProfileInspector.cs b/Editor/BaseSurfaceObserverProfileInspector.cs new file mode 100644 index 0000000..4e1c914 --- /dev/null +++ b/Editor/BaseSurfaceObserverProfileInspector.cs @@ -0,0 +1,72 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.Editor; +using UnityEditor; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Editor +{ + [CustomEditor(typeof(BaseSurfaceObserverProfile), true, isFallback = true)] + public class BaseSurfaceObserverProfileInspector : BaseSpatialObserverProfileInspector + { + private readonly GUIContent surfaceFoldoutContent = new GUIContent("Surface Finding Settings"); + + private SerializedProperty surfaceFindingMinimumArea; + private SerializedProperty displayFloorSurfaces; + private SerializedProperty floorSurfaceMaterial; + private SerializedProperty displayCeilingSurfaces; + private SerializedProperty ceilingSurfaceMaterial; + private SerializedProperty displayWallSurfaces; + private SerializedProperty wallSurfaceMaterial; + private SerializedProperty displayPlatformSurfaces; + private SerializedProperty platformSurfaceMaterial; + + private readonly GUIContent ceilingMaterialContent = new GUIContent("Ceiling Material"); + private readonly GUIContent floorMaterialContent = new GUIContent("Floor Material"); + private readonly GUIContent platformMaterialContent = new GUIContent("Platform Material"); + private readonly GUIContent wallMaterialContent = new GUIContent("Wall Material"); + private readonly GUIContent minimumAreaContent = new GUIContent("Minimum Area"); + + /// + protected override void OnEnable() + { + base.OnEnable(); + + surfaceFindingMinimumArea = serializedObject.FindProperty(nameof(surfaceFindingMinimumArea)); + displayFloorSurfaces = serializedObject.FindProperty(nameof(displayFloorSurfaces)); + floorSurfaceMaterial = serializedObject.FindProperty(nameof(floorSurfaceMaterial)); + displayCeilingSurfaces = serializedObject.FindProperty(nameof(displayCeilingSurfaces)); + ceilingSurfaceMaterial = serializedObject.FindProperty(nameof(ceilingSurfaceMaterial)); + displayWallSurfaces = serializedObject.FindProperty(nameof(displayWallSurfaces)); + wallSurfaceMaterial = serializedObject.FindProperty(nameof(wallSurfaceMaterial)); + displayPlatformSurfaces = serializedObject.FindProperty(nameof(displayPlatformSurfaces)); + platformSurfaceMaterial = serializedObject.FindProperty(nameof(platformSurfaceMaterial)); + } + + /// + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + if (surfaceFindingMinimumArea.FoldoutWithBoldLabelPropertyField(surfaceFoldoutContent, minimumAreaContent)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(displayFloorSurfaces); + EditorGUILayout.PropertyField(floorSurfaceMaterial, floorMaterialContent); + EditorGUILayout.PropertyField(displayCeilingSurfaces); + EditorGUILayout.PropertyField(ceilingSurfaceMaterial, ceilingMaterialContent); + EditorGUILayout.PropertyField(displayWallSurfaces); + EditorGUILayout.PropertyField(wallSurfaceMaterial, wallMaterialContent); + EditorGUILayout.PropertyField(displayPlatformSurfaces); + EditorGUILayout.PropertyField(platformSurfaceMaterial, platformMaterialContent); + EditorGUI.indentLevel--; + } + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Editor/BaseSurfaceObserverProfileInspector.cs.meta b/Editor/BaseSurfaceObserverProfileInspector.cs.meta new file mode 100644 index 0000000..39619b4 --- /dev/null +++ b/Editor/BaseSurfaceObserverProfileInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7052291bd6684f0b88835c08ed3937ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 6e2e9d716bbb4d8382bd53f11996b90e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/RealityToolkit.SpatialAwareness.Editor.asmdef b/Editor/RealityToolkit.SpatialAwareness.Editor.asmdef index 594f524..895d066 100644 --- a/Editor/RealityToolkit.SpatialAwareness.Editor.asmdef +++ b/Editor/RealityToolkit.SpatialAwareness.Editor.asmdef @@ -8,7 +8,8 @@ "GUID:9753fcbb5b1feaf459f435ac95e51baa", "GUID:b2d046948d6452a4b8485efc9ce0f88c", "GUID:2a3f0ca4e21332c44bfdce311ea8943e", - "GUID:4ddd23ea56a3a40f0aa0036d1624a53e" + "GUID:4ddd23ea56a3a40f0aa0036d1624a53e", + "GUID:35678c06c8d288749857954cda15bcab" ], "includePlatforms": [ "Editor" diff --git a/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs b/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs new file mode 100644 index 0000000..d5c91d2 --- /dev/null +++ b/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs @@ -0,0 +1,37 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Services; +using RealityCollective.Utilities.Editor; +using RealityToolkit.SpatialAwareness.Definitions; +using UnityEditor; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Editor +{ + [InitializeOnLoad] + public static class EditorActiveProfileChangeHandler + { + static EditorActiveProfileChangeHandler() + { + EditorApplication.hierarchyChanged += EditorApplication_hierarchyChanged; + } + + private static void EditorApplication_hierarchyChanged() + { + if (ServiceManager.IsActiveAndInitialized) + { + if (ServiceManager.Instance.TryGetService(out _) && + LayerUtilities.CheckLayers(SpatialAwarenessSystemProfile.SpatialAwarenessLayers)) + { + Debug.Log($"{nameof(ISpatialAwarenessService)} was enabled, spatial mapping layers added to project."); + } + else if (!ServiceManager.Instance.TryGetService(out _) && + LayerUtilities.RemoveLayers(SpatialAwarenessSystemProfile.SpatialAwarenessLayers)) + { + Debug.Log($"{nameof(ISpatialAwarenessService)} was disabled, spatial mapping layers removed to project."); + } + } + } + } +} diff --git a/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs.meta b/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs.meta new file mode 100644 index 0000000..4cf4ac0 --- /dev/null +++ b/Editor/SpatialAwarenessEditorActiveProfileChangeHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9daeda13d83550e4aba46e9202489951 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SpatialAwarenessPackageModulesInstaller.cs b/Editor/SpatialAwarenessPackageModulesInstaller.cs index 674f916..fc3e7dc 100644 --- a/Editor/SpatialAwarenessPackageModulesInstaller.cs +++ b/Editor/SpatialAwarenessPackageModulesInstaller.cs @@ -4,19 +4,21 @@ using RealityCollective.ServiceFramework.Definitions; using RealityCollective.ServiceFramework.Editor.Packages; using RealityCollective.ServiceFramework.Services; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System.Linq; using UnityEditor; namespace RealityToolkit.SpatialAwareness.Editor { /// - /// Installs s coming from a third party package - /// into the in the . + /// Installs the spatial awareness package modules in the . /// [InitializeOnLoad] public sealed class SpatialAwarenessPackageModulesInstaller : IPackageModulesInstaller { /// - /// Static initializer for the installer instance. + /// Statis initalizer for the installer instance. /// static SpatialAwarenessPackageModulesInstaller() { @@ -36,57 +38,44 @@ static SpatialAwarenessPackageModulesInstaller() /// public bool Install(ServiceConfiguration serviceConfiguration) { - /* - ------------------------------------------------------- - TO install modules for the service, uncomment the code below. - - Note, in order to correctly assign modules for the service, you need to replace the following (Where spatial_awareness is the service name used to generate this repository): - - - spatial_awareness with the correct service type. - - spatial_awarenessModule with the correct module type. - - Ispatial_awarenessModule with the correct module interface. - - spatial_awarenessProfile with the correct profile type. + if (!typeof(ISpatialAwarenessServiceModule).IsAssignableFrom(serviceConfiguration.InstancedType.Type)) + { + // This module installer does not accept the configuration type. + return false; + } - These are collated from the service and module definitions generated using the Service Template Generator - ------------------------------------------------------- - if (!typeof(Ispatial_awarenessModule).IsAssignableFrom(serviceConfiguration.InstancedType.Type)) - { - // This module installer does not accept the configuration type. - return false; - } + if (!ServiceManager.IsActiveAndInitialized) + { + UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(ServiceManager)} is not initialized."); + return false; + } - if (!ServiceManager.IsActiveAndInitialized) - { - UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(ServiceManager)} is not initialized."); - return false; - } + if (!ServiceManager.Instance.HasActiveProfile) + { + UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(ServiceManager)} has no active profile."); + return false; + } - if (!ServiceManager.Instance.HasActiveProfile) - { - UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(ServiceManager)} has no active profile."); - return false; - } + if (!ServiceManager.Instance.TryGetServiceProfile(out var spatialAwarenessServiceProfile)) + { + UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(SpatialAwarenessSystemProfile)} not found."); + return false; + } - if (!ServiceManager.Instance.TryGetServiceProfile(out var spatial_awarenessProfile)) - { - UnityEngine.Debug.LogWarning($"Could not install {serviceConfiguration.InstancedType.Type.Name}.{nameof(spatial_awarenessProfile)} not found."); - return false; - } + // Setup the configuration. + var typedServiceConfiguration = new ServiceConfiguration(serviceConfiguration.InstancedType.Type, serviceConfiguration.Name, serviceConfiguration.Priority, serviceConfiguration.RuntimePlatforms, serviceConfiguration.Profile); - // Setup the configuration. - var typedServiceConfiguration = new ServiceConfiguration(serviceConfiguration.InstancedType.Type, serviceConfiguration.Name, serviceConfiguration.Priority, serviceConfiguration.RuntimePlatforms, serviceConfiguration.Profile); + // Make sure it's not already in the target profile. + if (spatialAwarenessServiceProfile.ServiceConfigurations.All(sc => sc.InstancedType.Type != serviceConfiguration.InstancedType.Type)) + { + spatialAwarenessServiceProfile.AddConfiguration(typedServiceConfiguration); + UnityEngine.Debug.Log($"Successfully installed the {serviceConfiguration.InstancedType.Type.Name} to {spatialAwarenessServiceProfile.name}."); + } + else + { + UnityEngine.Debug.Log($"Skipped installing the {serviceConfiguration.InstancedType.Type.Name} to {spatialAwarenessServiceProfile.name}. Already installed."); + } - // Make sure it is not already in the target profile. - if (spatial_awarenessProfile.ServiceConfigurations.All(sc => sc.InstancedType.Type != serviceConfiguration.InstancedType.Type)) - { - spatial_awarenessProfile.AddConfiguration(typedServiceConfiguration); - UnityEngine.Debug.Log($"Successfully installed the {serviceConfiguration.InstancedType.Type.Name} to {spatial_awarenessProfile.name}."); - } - else - { - UnityEngine.Debug.Log($"Skipped installing the {serviceConfiguration.InstancedType.Type.Name} to {spatial_awarenessProfile.name}. Already installed."); - } - */ return true; } } diff --git a/Editor/SpatialAwarenessSserviceProfileInspector.cs b/Editor/SpatialAwarenessSserviceProfileInspector.cs new file mode 100644 index 0000000..9305a7b --- /dev/null +++ b/Editor/SpatialAwarenessSserviceProfileInspector.cs @@ -0,0 +1,53 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Editor.Profiles; +using RealityToolkit.Editor; +using RealityToolkit.SpatialAwareness.Definitions; +using UnityEditor; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Editor +{ + [CustomEditor(typeof(SpatialAwarenessSystemProfile))] + public class SpatialAwarenessSystemProfileInspector : ServiceProfileInspector + { + private SerializedProperty meshDisplayOption; + private SerializedProperty globalMeshObserverProfile; + private SerializedProperty globalSurfaceObserverProfile; + + private readonly GUIContent generalSettingsFoldoutHeader = new GUIContent("General Settings"); + + /// + protected override void OnEnable() + { + base.OnEnable(); + + meshDisplayOption = serializedObject.FindProperty(nameof(meshDisplayOption)); + meshDisplayOption.isExpanded = true; + globalMeshObserverProfile = serializedObject.FindProperty(nameof(globalMeshObserverProfile)); + globalSurfaceObserverProfile = serializedObject.FindProperty(nameof(globalSurfaceObserverProfile)); + } + + /// + protected override void RenderConfigurationOptions(bool forceExpanded = false) + { + RenderHeader("Spatial Awareness can enhance your experience by enabling objects to interact with the real world.\n\nBelow is a list of registered Spatial Observers that can gather data about your environment."); + + serializedObject.Update(); + + if (meshDisplayOption.FoldoutWithBoldLabelPropertyField(generalSettingsFoldoutHeader)) + { + EditorGUILayout.Space(); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(globalMeshObserverProfile); + EditorGUILayout.PropertyField(globalSurfaceObserverProfile); + EditorGUI.indentLevel--; + } + + DrawServiceModulePropertyDrawer(); + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/Editor/SpatialAwarenessSserviceProfileInspector.cs.meta b/Editor/SpatialAwarenessSserviceProfileInspector.cs.meta new file mode 100644 index 0000000..651d7cf --- /dev/null +++ b/Editor/SpatialAwarenessSserviceProfileInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04221c08803841039e2565acde6fee74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 6e2e9d716bbb4d8382bd53f11996b90e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions.meta b/Runtime/Definitions.meta new file mode 100644 index 0000000..f83834f --- /dev/null +++ b/Runtime/Definitions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a29a368d50cd4cf41bede519d94e4f63 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs b/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs new file mode 100644 index 0000000..738894f --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs @@ -0,0 +1,32 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// Enumeration defining levels of detail for the spatial awareness service. + /// + public enum SpatialAwarenessMeshLevelOfDetail + { + /// + /// The low level of detail is well suited for identifying large + /// environmental features, such as floors and walls. + /// + Low = 0, + + /// + /// The medium level of detail is suited for fast environmental mesh occlusion. + /// + Medium = 1, + + /// + /// The high level of detail is well suited for mesh occlusion for object like hands. + /// + High = 2, + + /// + /// A custom level of detail which is overridden by the platform specific profile. + /// + Custom = 3 + } +} diff --git a/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs.meta b/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs.meta new file mode 100644 index 0000000..18c7a5c --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessMeshLevelOfDetail.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 070fd5bf1b0f45769f1c7b5d6adddafd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialAwarenessServiceProfile.cs b/Runtime/Definitions/SpatialAwarenessServiceProfile.cs new file mode 100644 index 0000000..2269ed4 --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessServiceProfile.cs @@ -0,0 +1,60 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Definitions; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// Configuration profile settings for setting up the spatial awareness system. + /// + public class SpatialAwarenessSystemProfile : BaseServiceProfile + { + public static readonly Tuple[] SpatialAwarenessLayers = + { + new Tuple(30, SpatialAwarenessMeshesLayerName), + new Tuple(31, SpatialAwarenessSurfacesLayerName) + }; + + /// + /// The name of the Spatial Awareness Mesh Physics Layer. + /// + public const string SpatialAwarenessMeshesLayerName = "Spatial Awareness Meshes"; + + /// + /// The name of the Spatial Awareness Surfaces Physics Layer. + /// + public const string SpatialAwarenessSurfacesLayerName = "Spatial Awareness Surfaces"; + + [SerializeField] + [Tooltip("Indicates how the BaseSpatialMeshObserver is to display surface meshes within the application.")] + private SpatialMeshDisplayOptions meshDisplayOption = SpatialMeshDisplayOptions.None; + + /// + /// Indicates how the is to display surface meshes within the application. + /// + public SpatialMeshDisplayOptions MeshDisplayOption => meshDisplayOption; + + [SerializeField] + [Tooltip("The global mesh observer profile settings to use for the mesh observer service module if no profile is provided.")] + private BaseSpatialMeshObserverProfile globalMeshObserverProfile = null; + + /// + /// The global mesh observer profile settings to use for the s if no profile is provided. + /// + public BaseSpatialMeshObserverProfile GlobalMeshObserverProfile => globalMeshObserverProfile; + + [SerializeField] + [Tooltip("The global mesh observer profile settings to use for the mesh observer service module if no profile is provided.")] + private BaseSurfaceObserverProfile globalSurfaceObserverProfile = null; + + /// + /// The global mesh observer profile settings to use for the s if no profile is provided. + /// + public BaseSurfaceObserverProfile GlobalSurfaceObserverProfile => globalSurfaceObserverProfile; + } +} diff --git a/Runtime/Definitions/SpatialAwarenessServiceProfile.cs.meta b/Runtime/Definitions/SpatialAwarenessServiceProfile.cs.meta new file mode 100644 index 0000000..f75e83c --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessServiceProfile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80a1ad34855542cbbd15a6a6dde2e935 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 9275054f8248b2f408eb427eaa609a58, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs b/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs new file mode 100644 index 0000000..eaa170c --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs @@ -0,0 +1,41 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// Enumeration defining the types of planar surfaces that are supported by the spatial awareness surface finding subsystem. + /// + [System.Flags] + public enum SpatialAwarenessSurfaceTypes + { + /// + /// An unknown / unsupported type of surface. + /// + Unknown = 1 << 0, + + /// + /// The environment’s floor. + /// + Floor = 1 << 1, + + /// + /// The environment’s ceiling. + /// + Ceiling = 1 << 2, + + /// + /// A wall within the user’s space. + /// + Wall = 1 << 3, + + /// + /// A raised, horizontal surface such as a shelf. + /// + /// + /// Platforms, like floors, that can be used for placing objects + /// requiring a horizontal surface. + /// + Platform = 1 << 4 + } +} diff --git a/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs.meta b/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs.meta new file mode 100644 index 0000000..43d9bf5 --- /dev/null +++ b/Runtime/Definitions/SpatialAwarenessSurfaceTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d88eef87bbe24202858d14941aa66c33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialMeshDisplayOptions.cs b/Runtime/Definitions/SpatialMeshDisplayOptions.cs new file mode 100644 index 0000000..f3d3bba --- /dev/null +++ b/Runtime/Definitions/SpatialMeshDisplayOptions.cs @@ -0,0 +1,31 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// Options for how the spatial mesh is to be displayed by the spatial awareness system. + /// + public enum SpatialMeshDisplayOptions + { + /// + /// Disable the spatial mesh renderer and collider. + /// + None = 0, + + /// + /// Display the spatial mesh using the configured material. + /// + Visible, + + /// + /// Display the spatial mesh using the configured occlusion material. + /// + Occlusion, + + /// + /// Only enable the collider for the spatial mesh object. + /// + Collision, + } +} \ No newline at end of file diff --git a/Runtime/Definitions/SpatialMeshDisplayOptions.cs.meta b/Runtime/Definitions/SpatialMeshDisplayOptions.cs.meta new file mode 100644 index 0000000..0f5dac2 --- /dev/null +++ b/Runtime/Definitions/SpatialMeshDisplayOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f836f941d69342bdac7acaba39587ecd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialMeshObject.cs b/Runtime/Definitions/SpatialMeshObject.cs new file mode 100644 index 0000000..6f38ac6 --- /dev/null +++ b/Runtime/Definitions/SpatialMeshObject.cs @@ -0,0 +1,85 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// A Spatial Mesh Object is the Spatial Awareness System's representation of a spatial object with mesh information. + /// + public struct SpatialMeshObject + { + /// + /// Constructor. + /// + /// + /// + public SpatialMeshObject(Guid id, GameObject gameObject) : this() + { + Id = id; + GameObject = gameObject; + LastUpdated = DateTimeOffset.MinValue; + } + + /// + /// The id of the spatial mesh object. + /// + public Guid Id { get; internal set; } + + private GameObject gameObject; + + /// + /// The reference of the Spatial Mesh Object. + /// + public GameObject GameObject + { + get => gameObject; + internal set + { + gameObject = value; + + Renderer = gameObject.GetComponent(); + Filter = gameObject.GetComponent(); + Collider = gameObject.GetComponent(); + } + } + + public Mesh Mesh + { + get => Filter.sharedMesh; + internal set + { + // Reset the surface mesh collider to fit the updated mesh. + // Unity tribal knowledge indicates that to change the mesh assigned to a + // mesh collider and mesh filter, the mesh must first be set to null. Presumably there + // is a side effect in the setter when setting the shared mesh to null. + Filter.sharedMesh = null; + Filter.sharedMesh = value; + Collider.sharedMesh = null; + Collider.sharedMesh = Filter.sharedMesh; + } + } + + /// + /// The reference for the Spatial Mesh Object. + /// + public MeshRenderer Renderer { get; private set; } + + /// + /// The reference for the Spatial Mesh Object. + /// + public MeshFilter Filter { get; private set; } + + /// + /// The reference for the Spatial Mesh Object. + /// + public MeshCollider Collider { get; private set; } + + /// + /// The last time this object was updated. + /// + public DateTimeOffset LastUpdated { get; set; } + } +} diff --git a/Runtime/Definitions/SpatialMeshObject.cs.meta b/Runtime/Definitions/SpatialMeshObject.cs.meta new file mode 100644 index 0000000..19b6cef --- /dev/null +++ b/Runtime/Definitions/SpatialMeshObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d5b5d326f2f4248844d855ef4d8beda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialObserverStatus.cs b/Runtime/Definitions/SpatialObserverStatus.cs new file mode 100644 index 0000000..bb94e74 --- /dev/null +++ b/Runtime/Definitions/SpatialObserverStatus.cs @@ -0,0 +1,26 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace RealityToolkit.SpatialAwareness.Definitions +{ + /// + /// Enumerates possible changes that may happen to a spatial observers + /// by the . + /// + public enum SpatialObserverStatus + { + /// + /// The spatial object was removed. This may happen with objects move outside of the spatial observer bounds, + /// when an environment changes in between spatial meshing updates, or when when the spatial observer was refined. + /// + Removed = 0, + /// + /// The spatial object was initially recognized and added to the list of tracked spatial objects. + /// + Added, + /// + /// The spatial object was already being observed but got updated. + /// + Updated + } +} diff --git a/Runtime/Definitions/SpatialObserverStatus.cs.meta b/Runtime/Definitions/SpatialObserverStatus.cs.meta new file mode 100644 index 0000000..1e8de2a --- /dev/null +++ b/Runtime/Definitions/SpatialObserverStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cee64cf971907e840b5d9a13d9c21c3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialObservers.meta b/Runtime/Definitions/SpatialObservers.meta new file mode 100644 index 0000000..cea4f1c --- /dev/null +++ b/Runtime/Definitions/SpatialObservers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4481d2e2371442c8a2d9be891960b531 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs b/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs new file mode 100644 index 0000000..b43efc4 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs @@ -0,0 +1,70 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework; +using RealityCollective.ServiceFramework.Attributes; +using RealityCollective.ServiceFramework.Definitions.Utilities; +using RealityToolkit.SpatialAwareness.Definitions; +using UnityEngine; + +namespace RealityToolkit.Definitions.SpatialObservers +{ + public class BaseSpatialMeshObserverProfile : BaseSpatialObserverProfile + { + [SerializeField] + [Tooltip("Level of detail for the mesh")] + private SpatialAwarenessMeshLevelOfDetail meshLevelOfDetail = SpatialAwarenessMeshLevelOfDetail.Low; + + /// + /// The desired Unity Physics Layer on which to set the spatial mesh. + /// + public SpatialAwarenessMeshLevelOfDetail MeshLevelOfDetail => meshLevelOfDetail; + + [SerializeField] + [Tooltip("Should normals be recalculated when a mesh is added or updated?")] + private bool meshRecalculateNormals = true; + + /// + /// Indicates if the spatial awareness system to generate normal for the returned meshes + /// as some platforms may not support returning normal along with the spatial mesh. + /// + public bool MeshRecalculateNormals => meshRecalculateNormals; + + [SerializeField] + [Tooltip("Material to use when displaying meshes")] + private Material meshVisibleMaterial = null; + + /// + /// The material to be used when automatically displaying spatial meshes. + /// + public Material MeshVisibleMaterial => meshVisibleMaterial; + + [SerializeField] + [Tooltip("Material to use when spatial meshes should occlude other objects")] + private Material meshOcclusionMaterial = null; + + /// + /// The material to be used when spatial meshes should occlude other objects. + /// + public Material MeshOcclusionMaterial => meshOcclusionMaterial; + + [SerializeField] + [Tooltip("Additional components to add to the generated spatial mesh GameObject")] + [SystemType(typeof(Component), TypeGrouping.ByAddComponentMenu)] + private SystemType[] additionalComponents = new SystemType[0]; + + /// + /// Additional s to add to the generated spatial mesh s + /// + public SystemType[] AdditionalComponents => additionalComponents; + + [SerializeField] + [Tooltip("Prefab to use for Object Pool instead of generated object.")] + private GameObject meshObjectPrefab = null; + + /// + /// Prefab to use for Object Pool instead of generated mesh object. + /// + public GameObject MeshObjectPrefab => meshObjectPrefab; + } +} \ No newline at end of file diff --git a/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs.meta b/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs.meta new file mode 100644 index 0000000..2bef718 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSpatialMeshObserverProfile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34e54930903b41a9bdcbe94df832101b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 9275054f8248b2f408eb427eaa609a58, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs b/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs new file mode 100644 index 0000000..c5670a3 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs @@ -0,0 +1,64 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Definitions; +using RealityCollective.ServiceFramework.Definitions.Utilities; +using RealityCollective.Utilities.Attributes; +using UnityEngine; + +namespace RealityToolkit.Definitions.SpatialObservers +{ + // No Scriptable Object Menu constructor attributes here, as this class is meant to be inherited. + + /// + /// Base Mixed Reality Observer Profile. + /// + public abstract class BaseSpatialObserverProfile : BaseProfile + { + [SerializeField] + [Tooltip("How should the spatial awareness observer behave at startup?")] + private AutoStartBehavior startupBehavior = AutoStartBehavior.AutoStart; + + /// + /// Indicates if the developer intends for the spatial awareness observer start immediately or wait for manual startup. + /// + public AutoStartBehavior StartupBehavior => startupBehavior; + + [SerializeField] + [Tooltip("The dimensions of the spatial observer volume, in meters.")] + private Vector3 observationExtents = Vector3.one * 3; + + /// + /// The size of the volume, in meters per axis, from which individual observations will be made. + /// + public Vector3 ObservationExtents => observationExtents; + + [SerializeField] + [Tooltip("Should the spatial observer remain in a fixed location?")] + private bool isStationaryObserver = false; + + /// + /// The size of the volume, in meters per axis, from which individual observations will be made. + /// + public bool IsStationaryObserver => isStationaryObserver; + + [SerializeField] + [Tooltip("How often, in seconds, should the spatial observer update?")] + private float updateInterval = 3.5f; + + /// + /// The frequency, in seconds, at which the spatial observer updates. + /// + public float UpdateInterval => updateInterval; + + [PhysicsLayer] + [SerializeField] + [Tooltip("Which physics layer should this spatial observer use to create it's objects?")] + private int physicsLayer = -1; + + /// + /// The physics layer that the spatial observer will use for it's spatial objects. + /// + public int PhysicsLayer => physicsLayer; + } +} \ No newline at end of file diff --git a/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs.meta b/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs.meta new file mode 100644 index 0000000..699e643 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSpatialObserverProfile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 048c415ed81a45218d1dbbd5a034fff7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 9275054f8248b2f408eb427eaa609a58, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs b/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs new file mode 100644 index 0000000..0db0c24 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs @@ -0,0 +1,96 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using UnityEngine; + +namespace RealityToolkit.Definitions.SpatialObservers +{ + // No Scriptable Object Menu constructor attributes here, as this class is meant to be inherited. + + /// + /// The base surface observer profile. + /// + public class BaseSurfaceObserverProfile : BaseSpatialObserverProfile + { + [SerializeField] + [Tooltip("The minimum area, in square meters, of the planar surfaces")] + private float surfaceFindingMinimumArea = 0.025f; + + /// + /// The minimum area, in square meters, of the planar surfaces. + /// + public float SurfaceFindingMinimumArea => surfaceFindingMinimumArea; + + [SerializeField] + [Tooltip("Automatically display floor surfaces?")] + private bool displayFloorSurfaces = false; + + /// + /// Indicates if the surface finding subsystem is to automatically display floor surfaces within the application. + /// + public bool DisplayFloorSurfaces => displayFloorSurfaces; + + [SerializeField] + [Tooltip("Material to use when displaying floor surfaces")] + private Material floorSurfaceMaterial = null; + + /// + /// The material to be used when automatically displaying floor surfaces. + /// + public Material FloorSurfaceMaterial => floorSurfaceMaterial; + + [SerializeField] + [Tooltip("Automatically display ceiling surfaces?")] + private bool displayCeilingSurfaces = false; + + /// + /// Indicates if the surface finding subsystem is to automatically display ceiling surfaces within the application. + /// + public bool DisplayCeilingSurface => displayCeilingSurfaces; + + [SerializeField] + [Tooltip("Material to use when displaying ceiling surfaces")] + private Material ceilingSurfaceMaterial = null; + + /// + /// The material to be used when automatically displaying ceiling surfaces. + /// + public Material CeilingSurfaceMaterial => ceilingSurfaceMaterial; + + [SerializeField] + [Tooltip("Automatically display wall surfaces?")] + private bool displayWallSurfaces = false; + + /// + /// Indicates if the surface finding subsystem is to automatically display wall surfaces within the application. + /// + public bool DisplayWallSurface => displayWallSurfaces; + + [SerializeField] + [Tooltip("Material to use when displaying wall surfaces")] + private Material wallSurfaceMaterial = null; + + /// + /// The material to be used when automatically displaying wall surfaces. + /// + public Material WallSurfaceMaterial => wallSurfaceMaterial; + + [SerializeField] + [Tooltip("Automatically display platform surfaces?")] + private bool displayPlatformSurfaces = false; + + /// + /// Indicates if the surface finding subsystem is to automatically display platform surfaces within the application. + /// + public bool DisplayPlatformSurfaces => displayPlatformSurfaces; + + [SerializeField] + [Tooltip("Material to use when displaying platform surfaces")] + private Material platformSurfaceMaterial = null; + + /// + /// The material to be used when automatically displaying platform surfaces. + /// + public Material PlatformSurfaceMaterial => platformSurfaceMaterial; + } +} \ No newline at end of file diff --git a/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs.meta b/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs.meta new file mode 100644 index 0000000..bd888f9 --- /dev/null +++ b/Runtime/Definitions/SpatialObservers/BaseSurfaceObserverProfile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81654571a71446ab9301d87206d6c0c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 9275054f8248b2f408eb427eaa609a58, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ISpatialAwarenessService.cs b/Runtime/ISpatialAwarenessService.cs new file mode 100644 index 0000000..8462187 --- /dev/null +++ b/Runtime/ISpatialAwarenessService.cs @@ -0,0 +1,158 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Interfaces; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness +{ + /// + /// The interface definition for Spatial Awareness features in the Reality Toolkit. + /// + public interface ISpatialAwarenessService : IEventService, IRealityToolkitService + { + /// + /// Parent which will encapsulate all of the spatial awareness system created scene objects. + /// + GameObject SpatialAwarenessRootParent { get; } + + /// + /// Parent which will encapsulate all of the system created s. + /// + GameObject SpatialMeshesParent { get; } + + /// + /// Parent which will encapsulate all of the system created mesh objects. + /// + GameObject SurfacesParent { get; } + + /// + /// Gets or sets the provided mesh on all the + /// + /// + /// Is is possible to override any previously set display options on any specific observers. + /// + SpatialMeshDisplayOptions SpatialMeshVisibility { get; set; } + + #region Observers Utilities + + /// + /// Indicates the current running state of the spatial awareness observer. + /// + bool IsObserverRunning(ISpatialAwarenessServiceModule observer); + + /// + /// Generates a new unique observer id. + /// + /// All s are required to call this method in their initialization. + /// a new unique Id for the observer. + uint GenerateNewObserverId(); + + /// + /// Starts / restarts the spatial observer. + /// + /// This will cause spatial awareness events to resume. + void StartObserver(ISpatialAwarenessServiceModule observer); + + /// + /// Stops / pauses the spatial observer. + /// + /// This will cause spatial awareness events to be suspended until ResumeObserver is called. + void SuspendObserver(ISpatialAwarenessServiceModule observer); + + /// + /// List of the spatial observers as detected by the spatial awareness system. + /// + HashSet DetectedSpatialObservers { get; } + + #endregion Observer Utilities + + #region Observer Events + + /// + /// Raise the event that a has been detected. + /// + void RaiseSpatialAwarenessObserverDetected(ISpatialAwarenessServiceModule observer); + + /// + /// Raise the event that a has been lost. + /// + void RaiseSpatialAwarenessObserverLost(ISpatialAwarenessServiceModule observer); + + #endregion Observer Events + + #region Mesh Events + + /// + /// The spatial awareness system will call the method to indicate a mesh has been added. + /// + /// + /// The mesh . + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseMeshAdded(ISpatialMeshObserver observer, SpatialMeshObject meshObject); + + /// + /// The spatial awareness system will call the method to indicate an existing mesh has been updated. + /// + /// + /// The mesh . + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseMeshUpdated(ISpatialMeshObserver observer, SpatialMeshObject meshObject); + + /// + /// The spatial awareness system will call the method to indicate an existing mesh has been removed. + /// + /// + /// The mesh . + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseMeshRemoved(ISpatialMeshObserver observer, SpatialMeshObject meshObject); + + #endregion Mesh Events + + #region Surface Finding Events + + /// + /// The spatial awareness system will call the method to indicate a planar surface has been added. + /// + /// + /// Value identifying the surface. + /// The surface . + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseSurfaceAdded(ISpatialSurfaceObserver observer, Guid surfaceId, GameObject surfaceObject); + + /// + /// The spatial awareness system will call the method to indicate an existing planar surface has been updated. + /// + /// + /// Value identifying the surface. + /// The surface . + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseSurfaceUpdated(ISpatialSurfaceObserver observer, Guid surfaceId, GameObject surfaceObject); + + /// + /// The spatial awareness system will call the method to indicate an existing planar surface has been removed. + /// + /// + /// Value identifying the surface. + /// + /// This method is to be called by implementations of the interface, and not by application code. + /// + void RaiseSurfaceRemoved(ISpatialSurfaceObserver observer, Guid surfaceId); + + #endregion Surface Finding Events + } +} diff --git a/Runtime/ISpatialAwarenessService.cs.meta b/Runtime/ISpatialAwarenessService.cs.meta new file mode 100644 index 0000000..bb3967a --- /dev/null +++ b/Runtime/ISpatialAwarenessService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 681b083370694bf1a10499ad8f70ea0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces.meta b/Runtime/Interfaces.meta new file mode 100644 index 0000000..f804a91 --- /dev/null +++ b/Runtime/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a9c8b770d6ac2c44acc9750d2dc2528 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/Handlers.meta b/Runtime/Interfaces/Handlers.meta new file mode 100644 index 0000000..c448681 --- /dev/null +++ b/Runtime/Interfaces/Handlers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d33afc1bc61941a79b6f92d487ead097 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs b/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs new file mode 100644 index 0000000..ee6b152 --- /dev/null +++ b/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs @@ -0,0 +1,31 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using UnityEngine.EventSystems; + +namespace RealityToolkit.SpatialAwareness.Interfaces.Handlers +{ + /// + /// The event handler for all Spatial Awareness Mesh Events. + /// + public interface ISpatialAwarenessMeshHandler : IEventSystemHandler + { + /// + /// Called when the spatial awareness mesh subsystem adds a mesh. + /// + /// Data describing the event. + void OnMeshAdded(SpatialAwarenessEventData eventData); + + /// + /// Called when the spatial awareness mesh subsystem updates an existing mesh. + /// + /// Data describing the event. + void OnMeshUpdated(SpatialAwarenessEventData eventData); + + /// + /// Called when the spatial awareness mesh subsystem removes an existing mesh. + /// + /// Data describing the event. + void OnMeshRemoved(SpatialAwarenessEventData eventData); + } +} diff --git a/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs.meta b/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs.meta new file mode 100644 index 0000000..a309949 --- /dev/null +++ b/Runtime/Interfaces/Handlers/ISpatialAwarenessMeshHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 691d0f6b1ffb4dd8945295ce02e9cb9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs b/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs new file mode 100644 index 0000000..a6879c7 --- /dev/null +++ b/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs @@ -0,0 +1,32 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using UnityEngine.EventSystems; + +namespace RealityToolkit.SpatialAwareness.Interfaces.Handlers +{ + /// + /// The event handler for all Spatial Awareness Surface Finding Events. + /// + /// + public interface ISpatialAwarenessSurfaceFindingHandler : IEventSystemHandler + { + /// + /// Called when the spatial awareness surface finding subsystem adds a new planar surface. + /// + /// Data describing the event. + void OnSurfaceAdded(SpatialAwarenessEventData eventData); + + /// + /// Called when the spatial awareness surface finding subsystem updates an existing planar surface. + /// + /// Data describing the event. + void OnSurfaceUpdated(SpatialAwarenessEventData eventData); + + /// + /// Called when the spatial awareness surface finding subsystem removes an existing planar surface. + /// + /// Data describing the event. + void OnSurfaceRemoved(SpatialAwarenessEventData eventData); + } +} diff --git a/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs.meta b/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs.meta new file mode 100644 index 0000000..d43f3f4 --- /dev/null +++ b/Runtime/Interfaces/Handlers/ISpatialAwarenessSurfaceFindingHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91d89d7fb06241279c8aff4a03f7b099 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/SpatialObservers.meta b/Runtime/Interfaces/SpatialObservers.meta new file mode 100644 index 0000000..fa5e00c --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7593af4ee4bd4171a4f1d28963fd23bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs b/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs new file mode 100644 index 0000000..d60d484 --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs @@ -0,0 +1,47 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Definitions.Utilities; +using RealityToolkit.Interfaces.Events; + +namespace RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers +{ + /// + /// The Mixed Reality Spatial Observer service module contract. + /// + public interface ISpatialAwarenessServiceModule : IRealityToolkitServiceModule, IEventSource + { + /// + /// The startup behavior of the hardware resource. + /// + AutoStartBehavior StartupBehavior { get; } + + /// + /// Gets or sets the frequency, in seconds, at which the spatial observer updates. + /// + float UpdateInterval { get; set; } + + /// + /// The global physics layer to use when creating spatial objects for this observer. + /// + /// + /// Some implementations may override this. + /// + int PhysicsLayer { get; set; } + + /// + /// Is the observer running (actively accumulating spatial data)? + /// + bool IsRunning { get; } + + /// + /// Start the observer. + /// + void StartObserving(); + + /// + /// Stop the observer. + /// + void StopObserving(); + } +} diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs.meta b/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs.meta new file mode 100644 index 0000000..2540e79 --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialAwarenessServiceModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be5b660fb0bc4c6a9384d953c769d2ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs b/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs new file mode 100644 index 0000000..eba8d74 --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs @@ -0,0 +1,96 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityToolkit.SpatialAwareness.Definitions; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers +{ + /// + /// The interface contract for Mixed Reality spatial observers. + /// + public interface ISpatialMeshObserver : ISpatialAwarenessServiceModule + { + /// + /// Gets or sets the level of detail, as a value, for the returned spatial mesh. + /// + SpatialAwarenessMeshLevelOfDetail MeshLevelOfDetail { get; } + + /// + /// Gets or sets a value indicating if the spatial awareness system to generate normal for the returned meshes + /// as some platforms may not support returning normal along with the spatial mesh. + /// + bool MeshRecalculateNormals { get; } + + /// + /// Gets or sets a value indicating how the mesh subsystem is to display surface meshes within the application. + /// + /// + /// Applications that wish to process the es should set this value to None. + /// + SpatialMeshDisplayOptions MeshDisplayOption { get; set; } + + /// + /// Gets or sets the to be used when displaying s. + /// + Material MeshVisibleMaterial { get; } + + /// + /// Gets or sets the to be used when s should occlude other objects. + /// + Material MeshOcclusionMaterial { get; } + + /// + /// Gets or sets the size of the volume, in meters per axis, from which individual observations will be made. + /// + Vector3 ObservationExtents { get; } + + /// + /// Should the observer remain stationary in the scene? + /// + /// + /// Set IsStationaryObserver set to false, to move the volume with the user. + /// If set to true, the origin will be 0,0,0 or the last known location. + /// + bool IsStationaryObserver { get; } + + /// + /// Gets or sets the origin of the observer. + /// + /// + /// Moving the observer origin allows the spatial awareness system to locate and discard meshes as the user + /// navigates the environment. + /// + Vector3 ObserverOrigin { get; } + + /// + /// Gets for sets the rotation of the observer + /// + Quaternion ObserverOrientation { get; } + + /// + /// The collection of mesh s that have been observed. + /// + IReadOnlyDictionary SpatialMeshObjects { get; } + + /// + /// Forwards mesh added event to the . + /// + /// The data. + void RaiseMeshAdded(SpatialMeshObject spatialMeshObject); + + /// + /// Forwards mesh updated event to the . + /// + /// The data. + void RaiseMeshUpdated(SpatialMeshObject spatialMeshObject); + + /// + /// Forwards mesh removed event to the . + /// + /// The data. + void RaiseMeshRemoved(SpatialMeshObject spatialMeshObject); + } +} diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs.meta b/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs.meta new file mode 100644 index 0000000..cf861de --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialMeshObserver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f5b7bbcea4c4722a76640bd43948763 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs b/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs new file mode 100644 index 0000000..b8d86ff --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs @@ -0,0 +1,69 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers +{ + public interface ISpatialSurfaceObserver : ISpatialAwarenessServiceModule + { + /// + /// Gets or sets the minimum surface area, in square meters, that must be satisfied before a surface is identified. + /// + float SurfaceFindingMinimumArea { get; } + + /// + /// Gets or sets a value indicating if the surface finding subsystem is to automatically display + /// floor surfaces within the application. When enabled, the surfaces will be added to the scene + /// and rendered using the configured . + /// + bool DisplayFloorSurfaces { get; set; } + + /// + /// Gets or sets the to be used when rendering floor surfaces. + /// + Material FloorSurfaceMaterial { get; } + + /// + /// Gets or sets a value indicating if the surface finding subsystem is to automatically display + /// ceiling surfaces within the application. When enabled, the surfaces will be added to the scene + /// and rendered using the configured . + /// + bool DisplayCeilingSurfaces { get; set; } + + /// + /// Gets or sets the to be used when rendering ceiling surfaces. + /// + Material CeilingSurfaceMaterial { get; } + + /// + /// Gets or sets a value indicating if the surface finding subsystem is to automatically display + /// wall surfaces within the application. When enabled, the surfaces will be added to the scene + /// and rendered using the configured . + /// + bool DisplayWallSurfaces { get; set; } + + /// + /// Gets or sets the to be used when rendering wall surfaces. + /// + Material WallSurfaceMaterial { get; } + + /// + /// Gets or sets a value indicating if the surface finding subsystem is to automatically display + /// horizontal platform surfaces within the application. When enabled, the surfaces will be added to the scene + /// and rendered using the configured . + /// + bool DisplayPlatformSurfaces { get; set; } + + /// + /// Gets or sets the to be used when rendering horizontal platform surfaces. + /// + Material PlatformSurfaceMaterial { get; } + + /// + /// Gets the collection of s being managed by the spatial awareness surface finding subsystem. + /// + IReadOnlyDictionary PlanarSurfaces { get; } + } +} \ No newline at end of file diff --git a/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs.meta b/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs.meta new file mode 100644 index 0000000..699b715 --- /dev/null +++ b/Runtime/Interfaces/SpatialObservers/ISpatialSurfaceObserver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a2aa939576e4e889bb5105c592d3eec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Modules.meta b/Runtime/Modules.meta new file mode 100644 index 0000000..2d957ea --- /dev/null +++ b/Runtime/Modules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5fa96f46161496a8bdf4527ae7b1320 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Modules/BaseSpatialMeshObserver.cs b/Runtime/Modules/BaseSpatialMeshObserver.cs new file mode 100644 index 0000000..30cbbb0 --- /dev/null +++ b/Runtime/Modules/BaseSpatialMeshObserver.cs @@ -0,0 +1,324 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Services; +using RealityCollective.Utilities.Async; +using RealityCollective.Utilities.Extensions; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Modules +{ + /// + /// Base class for spatial awareness observers. + /// + public abstract class BaseSpatialMeshObserver : BaseSpatialObserverServiceModule, ISpatialMeshObserver + { + /// + protected BaseSpatialMeshObserver(string name, uint priority, BaseSpatialMeshObserverProfile profile, ISpatialAwarenessService parentService) + : base(name, priority, profile, parentService) + { + if (profile.IsNull()) + { + profile = ServiceManager.Instance.TryGetServiceProfile(out var spatialAwarenessSystemProfile) + ? spatialAwarenessSystemProfile.GlobalMeshObserverProfile + : throw new ArgumentException($"Unable to get a valid {nameof(SpatialAwarenessSystemProfile)}!"); + } + + if (profile.IsNull()) + { + throw new ArgumentNullException($"Missing a {profile.GetType().Name} profile for {name}"); + } + + MeshLevelOfDetail = profile.MeshLevelOfDetail; + MeshRecalculateNormals = profile.MeshRecalculateNormals; + meshDisplayOption = parentService.SpatialMeshVisibility; + MeshVisibleMaterial = profile.MeshVisibleMaterial; + MeshOcclusionMaterial = profile.MeshOcclusionMaterial; + ObservationExtents = profile.ObservationExtents; + IsStationaryObserver = profile.IsStationaryObserver; + var additionalComponents = profile.AdditionalComponents; + meshObjectPrefab = profile.MeshObjectPrefab; + spatialMeshObjectPool = new Stack(); + + if (additionalComponents != null) + { + requiredMeshComponents = new Type[additionalComponents.Length + 3]; + requiredMeshComponents[0] = typeof(MeshFilter); + requiredMeshComponents[1] = typeof(MeshRenderer); + requiredMeshComponents[2] = typeof(MeshCollider); + + for (int i = 3; i < additionalComponents.Length; i++) + { + var component = additionalComponents[i - 3].Type; + Debug.Assert(component != null); + requiredMeshComponents[i] = component; + } + } + else + { + requiredMeshComponents = new[] + { + typeof(MeshFilter), + typeof(MeshRenderer), + typeof(MeshCollider) + }; + } + } + + private readonly GameObject meshObjectPrefab; + + /// + /// When a mesh is created we will need to create a game object with a minimum + /// set of components to contain the mesh. These are the required component types. + /// + private readonly Type[] requiredMeshComponents; + + #region IService Implementation + + /// + public override void Initialize() + { + base.Initialize(); + + if (!Application.isPlaying) { return; } + + for (int i = 0; i < 10; i++) + { + spatialMeshObjectPool.Push(new SpatialMeshObject(Guid.Empty, CreateBlankSpatialMeshGameObject())); + } + } + + /// + public override void Start() + { + base.Start(); + + if (!Application.isPlaying) { return; } + + // If we've got some spatial meshes and were disabled previously, turn them back on. + foreach (var meshObject in spatialMeshObjects.Values) + { + meshObject.GameObject.SetActive(true); + } + } + + /// + public override void Update() + { + base.Update(); + + if (!Application.isPlaying || !IsRunning) { return; } + + lock (spatialMeshObjectPool) + { + // if we get low in our object pool, then create a few more. + if (spatialMeshObjectPool.Count < 5) + { + spatialMeshObjectPool.Push(new SpatialMeshObject(Guid.Empty, CreateBlankSpatialMeshGameObject())); + } + } + } + + /// + public override void Destroy() + { + base.Destroy(); + + if (!Application.isPlaying) { return; } + + spatialMeshObjects.Clear(); + + lock (spatialMeshObjectPool) + { + while (spatialMeshObjectPool.Count > 0) + { + var meshObject = spatialMeshObjectPool.Pop(); + meshObject.GameObject.Destroy(); + } + + Debug.Assert(spatialMeshObjectPool.Count == 0); + } + } + + #endregion IService Implementation + + #region ISpatialMeshObserver Implementation + + /// + public SpatialAwarenessMeshLevelOfDetail MeshLevelOfDetail { get; set; } + + /// + public bool MeshRecalculateNormals { get; } + + private SpatialMeshDisplayOptions meshDisplayOption; + + /// + public SpatialMeshDisplayOptions MeshDisplayOption + { + get => meshDisplayOption; + set + { + meshDisplayOption = value; + + if (meshDisplayOption != SpatialMeshDisplayOptions.None) + { + foreach (var spatialMeshObject in SpatialMeshObjects) + { + spatialMeshObject.Value.Collider.enabled = true; + spatialMeshObject.Value.Renderer.enabled = meshDisplayOption == SpatialMeshDisplayOptions.Visible || + meshDisplayOption == SpatialMeshDisplayOptions.Occlusion; + spatialMeshObject.Value.Renderer.sharedMaterial = meshDisplayOption == SpatialMeshDisplayOptions.Visible + ? MeshVisibleMaterial + : MeshOcclusionMaterial; + } + } + else + { + foreach (var spatialMeshObject in SpatialMeshObjects) + { + spatialMeshObject.Value.Renderer.enabled = false; + spatialMeshObject.Value.Collider.enabled = false; + } + } + } + } + + /// + public Material MeshVisibleMaterial { get; } + + /// + public Material MeshOcclusionMaterial { get; } + + /// + public Vector3 ObservationExtents { get; } + + /// + public bool IsStationaryObserver { get; } + + /// + public Vector3 ObserverOrigin { get; protected set; } = Vector3.zero; + + /// + public Quaternion ObserverOrientation { get; protected set; } = Quaternion.identity; + + private readonly Dictionary spatialMeshObjects = new Dictionary(); + + /// + /// + /// This method returns a copy of the collection maintained by the observer so that application + /// code can iterate through the collection without concern for changes to the backing data. + /// + public IReadOnlyDictionary SpatialMeshObjects => new Dictionary(spatialMeshObjects); + + private readonly Stack spatialMeshObjectPool; + + /// + public virtual void RaiseMeshAdded(SpatialMeshObject spatialMeshObject) + { + SpatialAwarenessSystem.RaiseMeshAdded(this, spatialMeshObject); + } + + /// + public virtual void RaiseMeshUpdated(SpatialMeshObject spatialMeshObject) + { + SpatialAwarenessSystem.RaiseMeshUpdated(this, spatialMeshObject); + } + + /// + public virtual void RaiseMeshRemoved(SpatialMeshObject spatialMeshObject) + { + if (spatialMeshObjects.TryGetValue(spatialMeshObject.Id, out var spatialMesh)) + { + spatialMeshObjects.Remove(spatialMesh.Id); + + // Raise mesh removed if it was prev enabled. + // spatialMesh.GameObject's only get enabled when successfully cooked. + // If it's disabled then likely the mesh was removed before cooking completed. + if (spatialMesh.GameObject.activeInHierarchy) + { + SpatialAwarenessSystem.RaiseMeshRemoved(this, spatialMeshObject); + } + + spatialMesh.GameObject.SetActive(false); + // Recycle this spatial mesh object and add it back to the pool. + spatialMesh.GameObject.name = "Reclaimed Spatial Mesh Object"; + spatialMesh.Mesh = null; + spatialMesh.Id = Guid.Empty; + spatialMesh.LastUpdated = DateTimeOffset.MinValue; + + lock (spatialMeshObjectPool) + { + spatialMeshObjectPool.Push(spatialMesh); + } + } + else + { + Debug.LogError($"{spatialMeshObject.Id} is missing from known spatial objects!"); + } + } + + /// + /// Request a from the collection of known spatial objects. If that object doesn't exist take one from our pool. + /// + /// The id of the . + /// A + protected async Task RequestSpatialMeshObject(Guid meshId) + { + if (spatialMeshObjects.TryGetValue(meshId, out var spatialMesh)) + { + return spatialMesh; + } + + lock (spatialMeshObjectPool) + { + if (spatialMeshObjectPool.Count > 0) + { + spatialMesh = spatialMeshObjectPool.Pop(); + spatialMesh.Id = meshId; + spatialMesh.GameObject.name = $"SpatialMesh_{meshId}"; + spatialMeshObjects.Add(spatialMesh.Id, spatialMesh); + return spatialMesh; + } + } + + await Awaiters.UnityMainThread; + return await RequestSpatialMeshObject(meshId); + } + + private GameObject CreateBlankSpatialMeshGameObject() + { + GameObject newGameObject; + + if (meshObjectPrefab.IsNull()) + { + newGameObject = new GameObject("Blank Spatial Mesh GameObject", requiredMeshComponents) + { + layer = PhysicsLayer + }; + } + else + { + newGameObject = UnityEngine.Object.Instantiate(meshObjectPrefab); + + for (var i = 0; i < requiredMeshComponents.Length; i++) + { + newGameObject.EnsureComponent(requiredMeshComponents[i]); + } + + newGameObject.layer = PhysicsLayer; + } + + newGameObject.transform.SetParent(SpatialAwarenessSystem.SpatialMeshesParent.transform, false); + newGameObject.SetActive(false); + return newGameObject; + } + + #endregion ISpatialMeshObserver Implementation + } +} diff --git a/Runtime/Modules/BaseSpatialMeshObserver.cs.meta b/Runtime/Modules/BaseSpatialMeshObserver.cs.meta new file mode 100644 index 0000000..6b6d927 --- /dev/null +++ b/Runtime/Modules/BaseSpatialMeshObserver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: faac94d34d98437e94e008e988c0516d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 661c780d86784e0b895a880d2624c8fe, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Modules/BaseSpatialObserverServiceModule.cs b/Runtime/Modules/BaseSpatialObserverServiceModule.cs new file mode 100644 index 0000000..5c3c4ab --- /dev/null +++ b/Runtime/Modules/BaseSpatialObserverServiceModule.cs @@ -0,0 +1,168 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Definitions.Utilities; +using RealityCollective.ServiceFramework.Modules; +using RealityCollective.ServiceFramework.Services; +using RealityCollective.Utilities.Extensions; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using System.Collections; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Modules +{ + /// + /// Base implementation + /// + public abstract class BaseSpatialObserverServiceModule : BaseServiceModule, ISpatialAwarenessServiceModule + { + /// + protected BaseSpatialObserverServiceModule(string name, uint priority, BaseSpatialObserverProfile profile, ISpatialAwarenessService parentService) + : base(name, priority, profile, parentService) + { + if (profile.IsNull()) + { + profile = ServiceManager.Instance.TryGetServiceProfile(out var spatialAwarenessSystemProfile) + ? spatialAwarenessSystemProfile.GlobalMeshObserverProfile + : throw new ArgumentException($"Unable to get a valid {nameof(SpatialAwarenessSystemProfile)}!"); + } + + if (profile.IsNull()) + { + throw new ArgumentNullException($"Missing a {profile.GetType().Name} profile for {name}"); + } + + SpatialAwarenessSystem = parentService; + SourceId = parentService.GenerateNewObserverId(); + StartupBehavior = profile.StartupBehavior; + UpdateInterval = profile.UpdateInterval; + PhysicsLayer = profile.PhysicsLayer; + } + + protected readonly ISpatialAwarenessService SpatialAwarenessSystem; + + #region IService Implementation + + /// + public override void Start() + { + base.Start(); + + SpatialAwarenessSystem.RaiseSpatialAwarenessObserverDetected(this); + + if (StartupBehavior == AutoStartBehavior.AutoStart) + { + StartObserving(); + } + } + + /// + public override void Destroy() + { + base.Destroy(); + + StopObserving(); + + SpatialAwarenessSystem.RaiseSpatialAwarenessObserverLost(this); + } + + #endregion IService Implementation + + #region ISpatialObserverDataProvider Implementation + + /// + public AutoStartBehavior StartupBehavior { get; } + + /// + public float UpdateInterval { get; set; } + + /// + public virtual int PhysicsLayer { get; set; } + + /// + public bool IsRunning { get; protected set; } + + /// + public virtual void StartObserving() + { + if (!Application.isPlaying) { return; } + IsRunning = true; + } + + /// + public virtual void StopObserving() + { + if (!Application.isPlaying) { return; } + IsRunning = false; + } + + #endregion ISpatialObserverDataProvider Implementation + + #region IEventSource Implementation + + /// + public string SourceName => Name; + + /// + public uint SourceId { get; } + + #endregion IEventSource Implementation + + #region IEquality Implementation + + /// + /// Determines if the specified objects are equal. + /// + /// + /// + /// + public static bool Equals(ISpatialAwarenessServiceModule left, ISpatialAwarenessServiceModule right) + { + return left.Equals(right); + } + + /// + bool IEqualityComparer.Equals(object left, object right) + { + return left.Equals(right); + } + + /// + public override bool Equals(object obj) + { + if (obj is null) { return false; } + if (ReferenceEquals(this, obj)) { return true; } + if (obj.GetType() != GetType()) { return false; } + + return Equals((ISpatialAwarenessServiceModule)obj); + } + + private bool Equals(ISpatialAwarenessServiceModule other) + { + return other != null && SourceId == other.SourceId && string.Equals(SourceName, other.SourceName); + } + + /// + int IEqualityComparer.GetHashCode(object obj) + { + return obj.GetHashCode(); + } + + /// + public override int GetHashCode() + { + unchecked + { + int hashCode = 0; + hashCode = (hashCode * 397) ^ (int)SourceId; + hashCode = (hashCode * 397) ^ (SourceName != null ? SourceName.GetHashCode() : 0); + return hashCode; + } + } + + #endregion IEquality Implementation + } +} \ No newline at end of file diff --git a/Runtime/Modules/BaseSpatialObserverServiceModule.cs.meta b/Runtime/Modules/BaseSpatialObserverServiceModule.cs.meta new file mode 100644 index 0000000..53b1d63 --- /dev/null +++ b/Runtime/Modules/BaseSpatialObserverServiceModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 762f0edb121b49d0bf13c0831145ab5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 661c780d86784e0b895a880d2624c8fe, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Modules/BaseSpatialSurfaceObserver.cs b/Runtime/Modules/BaseSpatialSurfaceObserver.cs new file mode 100644 index 0000000..fcf6d78 --- /dev/null +++ b/Runtime/Modules/BaseSpatialSurfaceObserver.cs @@ -0,0 +1,79 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Services; +using RealityCollective.Utilities.Extensions; +using RealityToolkit.Definitions.SpatialObservers; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RealityToolkit.SpatialAwareness.Modules +{ + /// + /// Base implementation. + /// + public abstract class BaseSpatialSurfaceObserver : BaseSpatialObserverServiceModule, ISpatialSurfaceObserver + { + /// + protected BaseSpatialSurfaceObserver(string name, uint priority, BaseSurfaceObserverProfile profile, ISpatialAwarenessService parentService) + : base(name, priority, profile, parentService) + { + if (profile.IsNull()) + { + profile = ServiceManager.Instance.TryGetServiceProfile(out var spatialAwarenessSystemProfile) + ? spatialAwarenessSystemProfile.GlobalSurfaceObserverProfile + : throw new ArgumentException($"Unable to get a valid {nameof(SpatialAwarenessSystemProfile)}!"); + } + + if (profile.IsNull()) + { + throw new ArgumentNullException($"Missing a {profile.GetType().Name} profile for {name}"); + } + + SurfaceFindingMinimumArea = profile.SurfaceFindingMinimumArea; + DisplayFloorSurfaces = profile.DisplayFloorSurfaces; + FloorSurfaceMaterial = profile.FloorSurfaceMaterial; + DisplayCeilingSurfaces = profile.DisplayCeilingSurface; + CeilingSurfaceMaterial = profile.CeilingSurfaceMaterial; + DisplayWallSurfaces = profile.DisplayWallSurface; + WallSurfaceMaterial = profile.WallSurfaceMaterial; + DisplayPlatformSurfaces = profile.DisplayPlatformSurfaces; + PlatformSurfaceMaterial = profile.PlatformSurfaceMaterial; + } + + /// + public float SurfaceFindingMinimumArea { get; } + + /// + public bool DisplayFloorSurfaces { get; set; } + + /// + public Material FloorSurfaceMaterial { get; } + + /// + public bool DisplayCeilingSurfaces { get; set; } + + /// + public Material CeilingSurfaceMaterial { get; } + + /// + public bool DisplayWallSurfaces { get; set; } + + /// + public Material WallSurfaceMaterial { get; } + + /// + public bool DisplayPlatformSurfaces { get; set; } + + /// + public Material PlatformSurfaceMaterial { get; } + + private readonly Dictionary planarSurfaces = new Dictionary(); + + /// + public IReadOnlyDictionary PlanarSurfaces => new Dictionary(planarSurfaces); + } +} \ No newline at end of file diff --git a/Runtime/Modules/BaseSpatialSurfaceObserver.cs.meta b/Runtime/Modules/BaseSpatialSurfaceObserver.cs.meta new file mode 100644 index 0000000..36f6e0f --- /dev/null +++ b/Runtime/Modules/BaseSpatialSurfaceObserver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f2ea5cdb7434c21a6a0c1bdf50df9b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 661c780d86784e0b895a880d2624c8fe, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SpatialAwarenessEventData.cs b/Runtime/SpatialAwarenessEventData.cs new file mode 100644 index 0000000..3bb830d --- /dev/null +++ b/Runtime/SpatialAwarenessEventData.cs @@ -0,0 +1,45 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityToolkit.EventDatum; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using System; +using UnityEngine.EventSystems; + +namespace RealityToolkit.SpatialAwareness +{ + /// + /// Data for spatial awareness events. + /// + public class SpatialAwarenessEventData : GenericBaseEventData + { + /// + /// Identifier of the object associated with this event. + /// + public Guid Id { get; private set; } + + /// + /// The spatial object managed by the spatial awareness system, representing the data in this event. + /// + public T SpatialObject { get; private set; } + + /// + /// Constructor. + /// + /// + public SpatialAwarenessEventData(EventSystem eventSystem) : base(eventSystem) { } + + /// + /// Used to initialize/reset the event and populate the data. + /// + /// + /// + /// + public void Initialize(ISpatialAwarenessServiceModule spatialAwarenessObserver, Guid id, T spatialObject) + { + BaseInitialize(spatialAwarenessObserver); + Id = id; + SpatialObject = spatialObject; + } + } +} diff --git a/Runtime/SpatialAwarenessEventData.cs.meta b/Runtime/SpatialAwarenessEventData.cs.meta new file mode 100644 index 0000000..58d6a16 --- /dev/null +++ b/Runtime/SpatialAwarenessEventData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57f0192ad8324cc2b4a6a7d8569b48da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SpatialAwarenessService.cs b/Runtime/SpatialAwarenessService.cs new file mode 100644 index 0000000..d05c22e --- /dev/null +++ b/Runtime/SpatialAwarenessService.cs @@ -0,0 +1,344 @@ +// Copyright (c) Reality Collective. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using RealityCollective.ServiceFramework.Attributes; +using RealityCollective.ServiceFramework.Definitions.Platforms; +using RealityCollective.ServiceFramework.Services; +using RealityCollective.Utilities.Extensions; +using RealityToolkit.SpatialAwareness.Definitions; +using RealityToolkit.SpatialAwareness.Interfaces.Handlers; +using RealityToolkit.SpatialAwareness.Interfaces.SpatialObservers; +using RealityToolkit.SpatialAwareness.Modules; +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace RealityToolkit.SpatialAwareness +{ + /// + /// Class providing the default implementation of the interface. + /// + [RuntimePlatform(typeof(AllPlatforms))] + [System.Runtime.InteropServices.Guid("05EF9DDC-13C2-47D4-84C5-1C9CB6CC5C1C")] + public class SpatialAwarenessService : BaseEventService, ISpatialAwarenessService + { + /// + /// Constructor. + /// + /// The service display name. + /// The service initialization priority. + /// The service configuration profile. + public SpatialAwarenessService(string name, uint priority, SpatialAwarenessSystemProfile profile) + : base(name, priority, profile) + { + spatialMeshVisibility = profile.MeshDisplayOption; + } + + private GameObject spatialAwarenessParent = null; + + /// + /// Parent which will encapsulate all of the spatial awareness system created scene objects. + /// + public GameObject SpatialAwarenessRootParent => spatialAwarenessParent != null ? spatialAwarenessParent : (spatialAwarenessParent = CreateSpatialAwarenessParent); + + /// + /// Creates the parent for spatial awareness objects so that the scene hierarchy does not get overly cluttered. + /// + /// + /// The to which spatial awareness created objects will be parented. + /// + private GameObject CreateSpatialAwarenessParent + { + get + { + var spatialAwarenessSystemObject = new GameObject("Spatial Awareness System"); + var rigTransform = Camera.main.transform.parent; + spatialAwarenessSystemObject.transform.SetParent(rigTransform, false); + return spatialAwarenessSystemObject; + } + } + + private GameObject meshParent = null; + + /// + public GameObject SpatialMeshesParent => meshParent != null ? meshParent : (meshParent = CreateSecondGenerationParent("Meshes")); + + private GameObject surfaceParent = null; + + /// + public GameObject SurfacesParent => surfaceParent != null ? surfaceParent : (surfaceParent = CreateSecondGenerationParent("Surfaces")); + + /// + public SpatialMeshDisplayOptions SpatialMeshVisibility + { + get => spatialMeshVisibility; + set + { + spatialMeshVisibility = value; + + foreach (var observer in DetectedSpatialObservers) + { + if (observer is BaseSpatialMeshObserver meshObserver) + { + meshObserver.MeshDisplayOption = spatialMeshVisibility; + } + } + } + } + + private SpatialMeshDisplayOptions spatialMeshVisibility; + + /// + /// Creates a parent that is a child of the Spatial Awareness System parent so that the scene hierarchy does not get overly cluttered. + /// + /// + /// The to which spatial awareness objects will be parented. + /// + private GameObject CreateSecondGenerationParent(string name) + { + var secondGeneration = new GameObject(name); + secondGeneration.transform.SetParent(SpatialAwarenessRootParent.transform, false); + return secondGeneration; + } + + #region ISpatialAwarenessSystem Implementation + + /// + public HashSet DetectedSpatialObservers { get; } = new HashSet(); + + /// + public bool IsObserverRunning(ISpatialAwarenessServiceModule observer) + { + foreach (var detectedObserver in DetectedSpatialObservers) + { + if (detectedObserver.SourceId == observer.SourceId) + { + return observer.IsRunning; + } + } + + return false; + } + + /// + public uint GenerateNewObserverId() + { + var newId = (uint)UnityEngine.Random.Range(1, int.MaxValue); + + foreach (var observer in DetectedSpatialObservers) + { + if (observer.SourceId == newId) + { + return GenerateNewObserverId(); + } + } + + return newId; + } + + /// + public void StartObserver(ISpatialAwarenessServiceModule observer) + { + foreach (var spatialObserver in DetectedSpatialObservers) + { + if (spatialObserver.SourceId == observer.SourceId) + { + spatialObserver.StartObserving(); + break; + } + } + } + + /// + public void SuspendObserver(ISpatialAwarenessServiceModule observer) + { + foreach (var spatialObserver in DetectedSpatialObservers) + { + if (spatialObserver.SourceId == observer.SourceId) + { + spatialObserver.StopObserving(); + break; + } + } + } + + /// + public void RaiseSpatialAwarenessObserverDetected(ISpatialAwarenessServiceModule observer) + { + DetectedSpatialObservers.Add(observer); + } + + /// + public void RaiseSpatialAwarenessObserverLost(ISpatialAwarenessServiceModule observer) + { + DetectedSpatialObservers.Remove(observer); + } + + #endregion ISpatialAwarenessSystem Implementation + + #region IService Implementation + + private SpatialAwarenessEventData meshEventData = null; + private SpatialAwarenessEventData surfaceFindingEventData = null; + + /// + public override void Initialize() + { + base.Initialize(); + + if (Application.isPlaying) + { + var eventSystem = EventSystem.current; + meshEventData = new SpatialAwarenessEventData(eventSystem); + surfaceFindingEventData = new SpatialAwarenessEventData(eventSystem); + } + } + + /// + public override void Destroy() + { + base.Destroy(); + + if (!Application.isPlaying) { return; } + + if (spatialAwarenessParent != null) + { + spatialAwarenessParent.transform.DetachChildren(); + spatialAwarenessParent.Destroy(); + } + + // Detach the mesh objects (they are to be cleaned up by the observer) and cleanup the parent + if (meshParent != null) + { + meshParent.transform.DetachChildren(); + meshParent.Destroy(); + } + + // Detach the surface objects (they are to be cleaned up by the observer) and cleanup the parent + if (surfaceParent != null) + { + surfaceParent.transform.DetachChildren(); + surfaceParent.Destroy(); + } + } + + #region Mesh Events + + /// + public void RaiseMeshAdded(ISpatialMeshObserver observer, SpatialMeshObject spatialMeshObject) + { + // Parent the mesh object + spatialMeshObject.GameObject.transform.parent = SpatialMeshesParent.transform; + + meshEventData.Initialize(observer, spatialMeshObject.Id, spatialMeshObject); + HandleEvent(meshEventData, OnMeshAdded); + } + + /// + /// Event sent whenever a mesh is added. + /// + private static readonly ExecuteEvents.EventFunction> OnMeshAdded = + delegate (ISpatialAwarenessMeshHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnMeshAdded(spatialEventData); + }; + + /// + public void RaiseMeshUpdated(ISpatialMeshObserver observer, SpatialMeshObject spatialMeshObject) + { + // Parent the mesh object + spatialMeshObject.GameObject.transform.parent = SpatialMeshesParent.transform; + + meshEventData.Initialize(observer, spatialMeshObject.Id, spatialMeshObject); + HandleEvent(meshEventData, OnMeshUpdated); + } + + /// + /// Event sent whenever a mesh is updated. + /// + private static readonly ExecuteEvents.EventFunction> OnMeshUpdated = + delegate (ISpatialAwarenessMeshHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnMeshUpdated(spatialEventData); + }; + + /// + public void RaiseMeshRemoved(ISpatialMeshObserver observer, SpatialMeshObject spatialMeshObject) + { + meshEventData.Initialize(observer, spatialMeshObject.Id, spatialMeshObject); + HandleEvent(meshEventData, OnMeshRemoved); + } + + /// + /// Event sent whenever a mesh is discarded. + /// + private static readonly ExecuteEvents.EventFunction> OnMeshRemoved = + delegate (ISpatialAwarenessMeshHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnMeshRemoved(spatialEventData); + }; + + #endregion Mesh Events + + #region Surface Finding Events + + /// + public void RaiseSurfaceAdded(ISpatialSurfaceObserver observer, Guid surfaceId, GameObject surfaceObject) + { + surfaceFindingEventData.Initialize(observer, surfaceId, surfaceObject); + HandleEvent(surfaceFindingEventData, OnSurfaceAdded); + } + + /// + /// Event sent whenever a planar surface is added. + /// + private static readonly ExecuteEvents.EventFunction> OnSurfaceAdded = + delegate (ISpatialAwarenessSurfaceFindingHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnSurfaceAdded(spatialEventData); + }; + + /// + public void RaiseSurfaceUpdated(ISpatialSurfaceObserver observer, Guid surfaceId, GameObject surfaceObject) + { + surfaceFindingEventData.Initialize(observer, surfaceId, surfaceObject); + HandleEvent(surfaceFindingEventData, OnSurfaceUpdated); + } + + /// + /// Event sent whenever a planar surface is updated. + /// + private static readonly ExecuteEvents.EventFunction> OnSurfaceUpdated = + delegate (ISpatialAwarenessSurfaceFindingHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnSurfaceUpdated(spatialEventData); + }; + + /// + public void RaiseSurfaceRemoved(ISpatialSurfaceObserver observer, Guid surfaceId) + { + surfaceFindingEventData.Initialize(observer, surfaceId, null); + HandleEvent(surfaceFindingEventData, OnSurfaceRemoved); + } + + /// + /// Event sent whenever a planar surface is discarded. + /// + private static readonly ExecuteEvents.EventFunction> OnSurfaceRemoved = + delegate (ISpatialAwarenessSurfaceFindingHandler handler, BaseEventData eventData) + { + var spatialEventData = ExecuteEvents.ValidateEventData>(eventData); + handler.OnSurfaceRemoved(spatialEventData); + }; + + #endregion Surface Finding Events + + #endregion IService Implementation + } +} diff --git a/Runtime/SpatialAwarenessService.cs.meta b/Runtime/SpatialAwarenessService.cs.meta new file mode 100644 index 0000000..4b0e524 --- /dev/null +++ b/Runtime/SpatialAwarenessService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95be363c06624d7cb40cb296aa02a5b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 8ac5213854cf4dbabd140decf8df1946, type: 3} + userData: + assetBundleName: + assetBundleVariant: