From 933e9f8d9e4f288cc248b78bf90a06b407bd6bf2 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Wed, 19 Jun 2024 10:59:14 +0200 Subject: [PATCH 01/21] WA now supports multiple trackable modules, add module mesh for iOS, capability are sent by module, moved prefab for arfoundation manager in resources folders --- Runtime/Materials.meta | 8 + Runtime/Materials/Blue.mat | 83 ++++ Runtime/Materials/Blue.mat.meta | 8 + Runtime/Materials/Green.mat | 83 ++++ Runtime/Materials/Green.mat.meta | 8 + Runtime/Materials/Red.mat | 83 ++++ Runtime/Materials/Red.mat.meta | 8 + Runtime/Resources.meta | 8 + .../Resources/ARFImageTrackingPrefab.prefab | 435 ++++++++++++++++++ .../ARFImageTrackingPrefab.prefab.meta | 7 + .../Resources/ARFMeshTrackingPrefab.prefab | 435 ++++++++++++++++++ .../ARFMeshTrackingPrefab.prefab.meta | 7 + Runtime/Resources/ARFObjectLibrary.asset | 17 + Runtime/Resources/ARFObjectLibrary.asset.meta | 8 + Runtime/Scripts/WorldAnalysisARFoundation.cs | 66 ++- .../WorldAnalysisARFoundationModule.cs | 10 +- .../WorldAnalysisARFoundationModuleImage.cs | 49 +- .../WorldAnalysisARFoundationModuleMesh.cs | 205 +++++++++ ...orldAnalysisARFoundationModuleMesh.cs.meta | 11 + 19 files changed, 1498 insertions(+), 41 deletions(-) create mode 100644 Runtime/Materials.meta create mode 100644 Runtime/Materials/Blue.mat create mode 100644 Runtime/Materials/Blue.mat.meta create mode 100644 Runtime/Materials/Green.mat create mode 100644 Runtime/Materials/Green.mat.meta create mode 100644 Runtime/Materials/Red.mat create mode 100644 Runtime/Materials/Red.mat.meta create mode 100644 Runtime/Resources.meta create mode 100644 Runtime/Resources/ARFImageTrackingPrefab.prefab create mode 100644 Runtime/Resources/ARFImageTrackingPrefab.prefab.meta create mode 100644 Runtime/Resources/ARFMeshTrackingPrefab.prefab create mode 100644 Runtime/Resources/ARFMeshTrackingPrefab.prefab.meta create mode 100644 Runtime/Resources/ARFObjectLibrary.asset create mode 100644 Runtime/Resources/ARFObjectLibrary.asset.meta create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs.meta diff --git a/Runtime/Materials.meta b/Runtime/Materials.meta new file mode 100644 index 0000000..a60af2e --- /dev/null +++ b/Runtime/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 573d01463f1ad468bafd74041040eeb1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Materials/Blue.mat b/Runtime/Materials/Blue.mat new file mode 100644 index 0000000..2adba28 --- /dev/null +++ b/Runtime/Materials/Blue.mat @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Blue + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Runtime/Materials/Blue.mat.meta b/Runtime/Materials/Blue.mat.meta new file mode 100644 index 0000000..97d3009 --- /dev/null +++ b/Runtime/Materials/Blue.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9fd9c0bd2f4f1438888297d0668f871b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Materials/Green.mat b/Runtime/Materials/Green.mat new file mode 100644 index 0000000..9037080 --- /dev/null +++ b/Runtime/Materials/Green.mat @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Green + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 1, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Runtime/Materials/Green.mat.meta b/Runtime/Materials/Green.mat.meta new file mode 100644 index 0000000..7612382 --- /dev/null +++ b/Runtime/Materials/Green.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de76e3ad692ba4492aaca3dd54e65f04 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Materials/Red.mat b/Runtime/Materials/Red.mat new file mode 100644 index 0000000..18e5576 --- /dev/null +++ b/Runtime/Materials/Red.mat @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Runtime/Materials/Red.mat.meta b/Runtime/Materials/Red.mat.meta new file mode 100644 index 0000000..166e41d --- /dev/null +++ b/Runtime/Materials/Red.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d815ae4d5a7b46ae99e4e5ed084d3a8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources.meta b/Runtime/Resources.meta new file mode 100644 index 0000000..b3b6637 --- /dev/null +++ b/Runtime/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edac3a3bd280a43d885c4cbb4296dc8d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources/ARFImageTrackingPrefab.prefab b/Runtime/Resources/ARFImageTrackingPrefab.prefab new file mode 100644 index 0000000..182f3b4 --- /dev/null +++ b/Runtime/Resources/ARFImageTrackingPrefab.prefab @@ -0,0 +1,435 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &760227130947233616 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5628977508733984536} + - component: {fileID: 1464890553281028111} + - component: {fileID: 6389761481980281444} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5628977508733984536 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1464890553281028111 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6389761481980281444 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &6911754431728604848 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754431728604849} + m_Layer: 0 + m_Name: ARFImageTrackingPrefab + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754431728604849 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754431728604848} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6911754432812775763} + - {fileID: 6911754433267149346} + - {fileID: 6911754433204531549} + - {fileID: 5628977508733984536} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6911754432812775762 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754432812775763} + - component: {fileID: 6911754432812775758} + - component: {fileID: 6911754432812775757} + - component: {fileID: 6911754432812775756} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754432812775763 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.0701} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11557999} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6911754432812775758 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754432812775757 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9fd9c0bd2f4f1438888297d0668f871b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754432812775756 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433204531548 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433204531549} + - component: {fileID: 6911754433204531544} + - component: {fileID: 6911754433204531551} + - component: {fileID: 6911754433204531550} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433204531549 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + serializedVersion: 2 + m_LocalRotation: {x: -0.5, y: -0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.0525, z: 0.0033} + m_LocalScale: {x: 0.0100000035, y: 0.01, z: 0.11558006} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: -90, y: -90.00001, z: 0} +--- !u!33 &6911754433204531544 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433204531551 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: de76e3ad692ba4492aaca3dd54e65f04, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433204531550 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433267149345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433267149346} + - component: {fileID: 6911754433267149341} + - component: {fileID: 6911754433267149340} + - component: {fileID: 6911754433267149347} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433267149346 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: -0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.0528, y: 0, z: 0.0033} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11558} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: -90, z: 0} +--- !u!33 &6911754433267149341 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433267149340 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9d815ae4d5a7b46ae99e4e5ed084d3a8, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433267149347 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} diff --git a/Runtime/Resources/ARFImageTrackingPrefab.prefab.meta b/Runtime/Resources/ARFImageTrackingPrefab.prefab.meta new file mode 100644 index 0000000..f1d093e --- /dev/null +++ b/Runtime/Resources/ARFImageTrackingPrefab.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a69d3cd9f6cbe4a7c8b7efc56da6dce9 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources/ARFMeshTrackingPrefab.prefab b/Runtime/Resources/ARFMeshTrackingPrefab.prefab new file mode 100644 index 0000000..6114fbe --- /dev/null +++ b/Runtime/Resources/ARFMeshTrackingPrefab.prefab @@ -0,0 +1,435 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &760227130947233616 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5628977508733984536} + - component: {fileID: 1464890553281028111} + - component: {fileID: 6389761481980281444} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5628977508733984536 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.05, y: 0.05, z: 0.05} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1464890553281028111 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6389761481980281444 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 760227130947233616} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &6911754431728604848 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754431728604849} + m_Layer: 0 + m_Name: ARFMeshTrackingPrefab + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754431728604849 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754431728604848} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6911754432812775763} + - {fileID: 6911754433267149346} + - {fileID: 6911754433204531549} + - {fileID: 5628977508733984536} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6911754432812775762 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754432812775763} + - component: {fileID: 6911754432812775758} + - component: {fileID: 6911754432812775757} + - component: {fileID: 6911754432812775756} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754432812775763 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.0701} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11557999} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6911754432812775758 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754432812775757 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9fd9c0bd2f4f1438888297d0668f871b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754432812775756 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433204531548 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433204531549} + - component: {fileID: 6911754433204531544} + - component: {fileID: 6911754433204531551} + - component: {fileID: 6911754433204531550} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433204531549 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + serializedVersion: 2 + m_LocalRotation: {x: -0.5, y: -0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.0525, z: 0.0033} + m_LocalScale: {x: 0.0100000035, y: 0.01, z: 0.11558006} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: -90, y: -90.00001, z: 0} +--- !u!33 &6911754433204531544 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433204531551 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: de76e3ad692ba4492aaca3dd54e65f04, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433204531550 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433267149345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433267149346} + - component: {fileID: 6911754433267149341} + - component: {fileID: 6911754433267149340} + - component: {fileID: 6911754433267149347} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433267149346 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: -0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.0528, y: 0, z: 0.0033} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11558} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: -90, z: 0} +--- !u!33 &6911754433267149341 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433267149340 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9d815ae4d5a7b46ae99e4e5ed084d3a8, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433267149347 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} diff --git a/Runtime/Resources/ARFMeshTrackingPrefab.prefab.meta b/Runtime/Resources/ARFMeshTrackingPrefab.prefab.meta new file mode 100644 index 0000000..f0e4eea --- /dev/null +++ b/Runtime/Resources/ARFMeshTrackingPrefab.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d9c86a0dba0134e8b8cdc67291dac135 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources/ARFObjectLibrary.asset b/Runtime/Resources/ARFObjectLibrary.asset new file mode 100644 index 0000000..a8b55ce --- /dev/null +++ b/Runtime/Resources/ARFObjectLibrary.asset @@ -0,0 +1,17 @@ +%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: 85f3b71a771f04aef8057fae3964fd78, type: 3} + m_Name: ARFObjectLibrary + m_EditorClassIdentifier: + m_GuidLow: 5086418788140608333 + m_GuidHigh: 13571590907545936521 + m_ReferenceObjects: [] diff --git a/Runtime/Resources/ARFObjectLibrary.asset.meta b/Runtime/Resources/ARFObjectLibrary.asset.meta new file mode 100644 index 0000000..859d813 --- /dev/null +++ b/Runtime/Resources/ARFObjectLibrary.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 487aef79f5a474b3aa285c3d2b2d29f3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 470bc31..bd82b85 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -26,9 +26,9 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface private Dictionary m_computedPoses; /// - /// Module Image + /// all trackable modules /// - private WorldAnalysisARFoundationModuleImage m_imageTrackableModule; + private List m_trackableModules; /// /// World Storage Info object @@ -72,8 +72,18 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface m_relocalizationInformations = new Dictionary(); m_computedPoses = new Dictionary(); m_subscriptionsPoses = new Dictionary(); - m_imageTrackableModule = new WorldAnalysisARFoundationModuleImage(); - m_imageTrackableModule.Initialize(); + + m_trackableModules = new List(); + WorldAnalysisARFoundationModuleImage imageModule = new WorldAnalysisARFoundationModuleImage(); + m_trackableModules.Add(imageModule); + #if UNITY_IOS + WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); + m_trackableModules.Add(meshModule); + #endif + foreach(WorldAnalysisARFoundationModule module in m_trackableModules) + { + module.Initialize(); + } m_storageInfo = FindObjectOfType(); m_worldStorageServer = m_storageInfo.worldStorageServer; @@ -136,7 +146,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface //We fill in the confidence level lists. foreach (KeyValuePair relocObject in temp) { - WorldAnalysisARFoundationModule.TrackableInfo inf = m_imageTrackableModule.GetPoseTrackable(relocObject.Value.Trackable.Name); // for now only image module + WorldAnalysisARFoundationModule.TrackableInfo inf = GetPoseTrackableUUID(relocObject.Value.Trackable.UUID); // for now only image module if (inf != null) { if (inf.confidence == 100) @@ -179,7 +189,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface if (bestTrackableCandidateID != Guid.Empty) { /// We have found the best trackable - WorldAnalysisARFoundationModule.TrackableInfo info = m_imageTrackableModule.GetPoseTrackable(temp[bestTrackableCandidateID].Trackable.Name); + WorldAnalysisARFoundationModule.TrackableInfo info = GetPoseTrackableUUID(temp[bestTrackableCandidateID].Trackable.UUID); if (info == null) { // For now we just ignore it : we could also send not tracked todo @@ -294,7 +304,6 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface return PoseEstimationResult.OK; } - public PoseEstimationResult[] GetLastPoses(string token, Guid[] uuids, Mode_WorldAnalysis[] modes, out ETSI.ARF.OpenAPI.WorldAnalysis.Pose[] poses) { if (uuids.Length != modes.Length) @@ -315,7 +324,6 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface return resul; } - public InformationSubscriptionResult SubscribeToPose(string token, Guid uuid, Mode_WorldAnalysis mode, PoseCallback callback, ref int validity, out Guid subscriptionUUID) { RelocalizationInformation relocInfo = null; @@ -469,19 +477,9 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface { List capabilitiesList = new List(); - /// Image Tracking - if (m_imageTrackableModule != null) + foreach(WorldAnalysisARFoundationModule module in m_trackableModules) { - ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityImage = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); - capabilityImage.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.IMAGE_MARKER; - ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); - encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.OTHER; - encodingInformation.Version = "1.01"; - capabilityImage.EncodingInformation = encodingInformation; - capabilityImage.Framerate = 30; // Not particularly specified on ARKit and ARCore - capabilityImage.Latency = 0; // Not particularly specified on ARKit and ARCore - capabilityImage.Accuracy = 1; // Not particularly specified on ARKit and ARCore - capabilitiesList.Add(capabilityImage); + capabilitiesList.Add(module.GetSupportedCapability()); } capabilities = capabilitiesList.ToArray(); @@ -501,6 +499,25 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface #region Helper + /// + /// Find in all modules the tracking info of a trackable with its name + /// + /// + /// Tracking info if found else null + private WorldAnalysisARFoundationModule.TrackableInfo GetPoseTrackableUUID(Guid uuid) + { + foreach (WorldAnalysisARFoundationModule module in m_trackableModules) + { + ///Improve latter : not good to check all modules + WorldAnalysisARFoundationModule.TrackableInfo info = module.GetPoseTrackable(uuid); + if (info !=null) + { + return info ; + } + } + return null ; + } + /// /// To select the best trackable /// @@ -510,7 +527,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface /// private Guid SelectTrackableWithTypeAndDistance(List candidates, List> typesSortedList, UnityEngine.Vector3 cameraTransformPos) { - float bestDistance = 100.0f; //valeur par défaut = grande distance (à changer) + float bestDistance = 100.0f; //valeur par d�faut = grande distance (� changer) Guid selectedTrackableUUID = Guid.Empty; //if only one trackable is candidate @@ -553,7 +570,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface // select the corresponding candidate from the list of candidates if (tmp.Trackable.UUID == distanceCandidate) { - WorldAnalysisARFoundationModule.TrackableInfo inf = m_imageTrackableModule.GetPoseTrackable(tmp.Trackable.Name); + WorldAnalysisARFoundationModule.TrackableInfo inf = GetPoseTrackableUUID(tmp.Trackable.UUID); float distance = UnityEngine.Vector3.Distance(cameraTransformPos, inf.position); @@ -578,10 +595,9 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface bool hasSupport = false; foreach (RelocObjects relocObj in relocInfo.RelocObjects) { - /// We try to find a supported trackable - if (relocObj.Trackable.TrackableType == ETSI.ARF.OpenAPI.WorldStorage.TrackableType.IMAGE_MARKER) + foreach(WorldAnalysisARFoundationModule module in m_trackableModules) { - hasSupport |= m_imageTrackableModule.AddTrackable(relocObj.Trackable); + hasSupport |= module.AddTrackable(relocObj.Trackable); } } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModule.cs b/Runtime/Scripts/WorldAnalysisARFoundationModule.cs index 3951fcc..4b9d745 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModule.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModule.cs @@ -1,4 +1,5 @@ using UnityEngine; +using System; public interface WorldAnalysisARFoundationModule { @@ -31,7 +32,12 @@ public interface WorldAnalysisARFoundationModule /// /// /// - /// - public TrackableInfo GetPoseTrackable(string name); + /// + public TrackableInfo GetPoseTrackable(Guid uuid); + + /// + /// Initialize capability object with the features of the + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability(); } \ No newline at end of file diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs index e7da9b2..4908f8b 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs @@ -23,9 +23,9 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod /// private Dictionary m_trackedImages = new Dictionary(); /// - /// Default Constructor + /// Link between trackable name and uuid /// - public WorldAnalysisARFoundationModuleImage() { } + private Dictionary m_uuidToName = new Dictionary(); /// /// Initialize image tracking module @@ -40,20 +40,20 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod } /// - /// found : pourrait aussi tracké pas tracké, on pourrait aussi ajouter la cofiance si dispo dans l'API + /// found /// - /// name of the image trackable - - public TrackableInfo GetPoseTrackable(string name) + /// name of the image trackable + public TrackableInfo GetPoseTrackable(Guid uuid) { - if (m_trackedImages.ContainsKey(name)) - { - return m_trackedImages[name]; - } - else + if (m_uuidToName.ContainsKey(uuid)) { - return null; + string name = m_uuidToName[uuid]; + if (m_trackedImages.ContainsKey(name)) + { + return m_trackedImages[name]; + } } + return null; } /// @@ -68,8 +68,29 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod { return false; } - AddImageToLibrary(trackable.Name, (float)trackable.TrackableSize[0]); - return true; + bool resul = AddImageToLibrary(trackable.Name, (float)trackable.TrackableSize[0]); + if (resul) + { + m_uuidToName[trackable.UUID] = trackable.Name; + } + return resul; + } + + /// + /// Initialize capability object with image tracking + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() + { + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityImage = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityImage.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.IMAGE_MARKER; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.OTHER; + encodingInformation.Version = "1.01"; + capabilityImage.EncodingInformation = encodingInformation; + capabilityImage.Framerate = 30; // Not particularly specified on ARKit and ARCore + capabilityImage.Latency = 0; // Not particularly specified on ARKit and ARCore + capabilityImage.Accuracy = 1; // Not particularly specified on ARKit and ARCore + return capabilityImage; } /// diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs new file mode 100644 index 0000000..77d841a --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.XR.ARFoundation; +using UnityEngine.XR.ARSubsystems; +using System.IO; +using Unity.XR.CoreUtils; +using static WorldAnalysisARFoundationModule; +using ETSI.ARF.OpenAPI.WorldStorage; + +public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModule +{ + /// + /// ARFoundation Image tracking management + /// + private ARTrackedObjectManager m_trackedObjectManager; + /// + /// Name of all meshes that have been added to the library + /// + private List m_trackedMeshesInLibrary; + /// + /// List of tracked meshses with tracking infos + /// + private Dictionary m_trackedMeshes = new Dictionary(); + /// + /// Link between trackable name and uuid + /// + private Dictionary m_uuidToName = new Dictionary(); + /// + /// Bundle with all the XRReferenceObjectEntry + /// + private XRReferenceObjectEntry [] m_entries ; + + /// + /// Initialize image tracking module + /// + public void Initialize() + { + XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); + m_trackedObjectManager = origin.gameObject.AddComponent(); + XRReferenceObjectLibrary library = (XRReferenceObjectLibrary) Resources.Load("ARFObjectLibrary"); + m_trackedObjectManager.referenceLibrary = library ; + m_trackedMeshesInLibrary = new List(); + m_trackedObjectManager.trackedObjectPrefab = (GameObject)Resources.Load("ARFMeshTrackingPrefab"); + m_trackedObjectManager.trackedObjectsChanged += OnTrackedMeshesChanged; + m_trackedObjectManager.enabled = true ; // when instantiated without library : it is disabled + m_entries = null; + + #if UNITY_EDITOR + string bundlePath = Application.streamingAssetsPath + "/arfmeshes" ; + #else + string bundlePath = Application.persistentDataPath + "/arfmeshes" ; + #endif + if (System.IO.File.Exists(bundlePath)) + { + AssetBundle bu = AssetBundle.LoadFromFile(bundlePath); + m_entries = bu.LoadAllAssets() ; + } + } + + /// + /// found + /// + /// name of the mesh trackable + public TrackableInfo GetPoseTrackable(Guid uuid) + { + if (m_uuidToName.ContainsKey(uuid)) + { + string name = m_uuidToName[uuid]; + if (m_trackedMeshes.ContainsKey(name)) + { + return m_trackedMeshes[name]; + } + } + return null; + } + + /// + /// Add a trackable : need to be an image + /// + /// Image trackable + /// Supported or not + public bool AddTrackable(Trackable trackable) + { + /// Here : we don't check if the trackable is allready added, AddMeshToLibrary does it + if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.MESH) + { + return false; + } + bool resul = AddMeshToLibrary(trackable.Name) ;// (float)trackable.TrackableSize[0]); + if (resul) + { + m_uuidToName[trackable.UUID] = trackable.Name; + } + return true; + } + + /// + /// Initialize capability object with image tracking + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() + { + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityMesh = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityMesh.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MESH; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARKIT; + encodingInformation.Version = "1.01"; + capabilityMesh.EncodingInformation = encodingInformation; + capabilityMesh.Framerate = 30; // Not particularly specified on ARKit + capabilityMesh.Latency = 0; // Not particularly specified on ARKit + capabilityMesh.Accuracy = 1; // Not particularly specified on ARKit + return capabilityMesh ; + } + + /// + /// Event manager for when a mesh is tracked + /// + /// the event + private void OnTrackedMeshesChanged(ARTrackedObjectsChangedEventArgs eventArgs) + { + foreach (var trackedMesh in eventArgs.updated) + { + Vector3 position = trackedMesh.transform.position; + Quaternion rotation = trackedMesh.transform.rotation; + + TrackableInfo info = new TrackableInfo(); + info.name = trackedMesh.referenceObject.name; + if (trackedMesh.trackingState == TrackingState.Tracking) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 100; + } + else if (trackedMesh.trackingState == TrackingState.Limited) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 50; + } + else + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.FAILURE; //ADD NOT_TRACKED ? + info.confidence = 0; + } + info.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + info.position = position; + info.rotation = rotation; + info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MESH; + m_trackedMeshes[info.name] = info; + } + } + + /// + /// Add a new mesh to the arfoundation library + /// + /// file name + /// + protected bool AddMeshToLibrary(string fileName) + { + // check if mesh is in the library + if (m_trackedMeshesInLibrary.Contains(fileName)) + { + Debug.Log("Mesh allready added to library"); + return true; + } + + if (m_entries == null) + { + Debug.LogWarning("Try to Track Mesh but ARF Bundle with meshes is null"); + return false ; + } + + XRReferenceObjectEntry toAdd = null ; + foreach(XRReferenceObjectEntry entry in m_entries) + { + if (entry.name == fileName) + { + toAdd = entry ; + } + } + if (toAdd == null) + { + Debug.LogWarning("Try to Track Mesh " + fileName + " but XRReferenceObjectEntry not found in bundle"); + return false; + } + + AddARObjectEntryToLibrary(toAdd , fileName); + return true; + } + + /// + /// Add a Mesh + /// + private async void AddARObjectEntryToLibrary(XRReferenceObjectEntry arobject , string objectName) + { + while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None) + { + await System.Threading.Tasks.Task.Delay(100); + } + + XRReferenceObject referenceObject = new XRReferenceObject(objectName); + referenceObject.AddEntry(arobject); + m_trackedObjectManager.referenceLibrary.Add(referenceObject); + + if (!m_trackedObjectManager.enabled) m_trackedObjectManager.enabled = true; // necessary because when object manger is instantiated without library it is disabled + } +} \ No newline at end of file diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs.meta new file mode 100644 index 0000000..6b5b5db --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 19f8755167c0547cab884eab1fc44dc1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab From af6828c50e1f75316a4297ed60d6eeb90af0875d Mon Sep 17 00:00:00 2001 From: jlacoche Date: Thu, 20 Jun 2024 10:38:55 +0200 Subject: [PATCH 02/21] Update documentation for meshes --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc9d00b..ae9dc0c 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,27 @@ This wrapper for the World Analysis relies on the ARFoundation (version 5.1.x) U Image markers are supported on both iOS and Android platforms through ARKit and ARCore. -The name of the Trackable in the World Storage must correspond to the name of a file (jpg or png) placed in the Unity persistent data path of the application on the user device. \ No newline at end of file +The name of the Trackable in the World Storage must correspond to the name of a file (jpg or png) placed in the Unity persistent data path of the application on the user device. + +More information about ARFoundation Image Tracking can be found here: https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/index.html + +### Mesh Trackables ### + +Mesh trackable are supported on iOS through ARKit. + +ARKit can track meshes that are defined in the .arobject format. Such an object can be scanned with the sample application provided here : https://developer.apple.com/documentation/arkit/arkit_in_ios/content_anchors/scanning_and_detecting_3d_objects + +Unity serializes .arobject into ARKitReferenceObjectEntry in the editor. ARKitReferenceObjectEntry cannot then be imported at runtime from a .arobjject file. Dynamic loading is not supported yet. + +To support adding .arobject without recompiling the full application, we use a dedicated AssetBundle (named "arfmeshes"). To do so: +* Place you .arobject in the Assets Folder. For instance under Assets/ARObjects +* Associate the ARKitReferenceObjectEntry with the arfmeshes AssetBundle in the editor +* Build the AssetBundles. For that you can use the following menu: ARF--> Build AssetBundles iOS +* Pace the "arfmeshes" file in the Unity persistent data path of the application on the user device. + +The name of the Trackable in the World Storage must correspond to the name of the ARKitReferenceObjectEntry. + +More information about ARFoundation Mesh Tracking can be found here: https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/features/object-tracking.html + + + -- GitLab From 47055f9ff8ca12ab43ed2fa8f66f2b84d8180ab0 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Tue, 25 Jun 2024 23:11:17 +0200 Subject: [PATCH 03/21] For mesh tracking instantiate XRReferenceObjectLibrary instead of loading it from resources --- Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs index 77d841a..8b85e15 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs @@ -38,7 +38,7 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu { XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); m_trackedObjectManager = origin.gameObject.AddComponent(); - XRReferenceObjectLibrary library = (XRReferenceObjectLibrary) Resources.Load("ARFObjectLibrary"); + XRReferenceObjectLibrary library = (XRReferenceObjectLibrary) ScriptableObject.CreateInstance(typeof(XRReferenceObjectLibrary)); m_trackedObjectManager.referenceLibrary = library ; m_trackedMeshesInLibrary = new List(); m_trackedObjectManager.trackedObjectPrefab = (GameObject)Resources.Load("ARFMeshTrackingPrefab"); -- GitLab From 25a53c5037e645114c9930a54c58c0e1e95d6653 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Tue, 25 Jun 2024 23:11:55 +0200 Subject: [PATCH 04/21] Add the support for downloading an image from a given url in keyvaluetags of the Trackable --- README.md | 6 +- .../WorldAnalysisARFoundationHelper.cs | 47 +++++++++++++++ .../WorldAnalysisARFoundationHelper.cs.meta | 11 ++++ .../WorldAnalysisARFoundationModuleImage.cs | 60 ++++++++++++++++--- 4 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationHelper.cs create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationHelper.cs.meta diff --git a/README.md b/README.md index ae9dc0c..497c9e5 100644 --- a/README.md +++ b/README.md @@ -24,15 +24,15 @@ This wrapper for the World Analysis relies on the ARFoundation (version 5.1.x) U Image markers are supported on both iOS and Android platforms through ARKit and ARCore. -The name of the Trackable in the World Storage must correspond to the name of a file (jpg or png) placed in the Unity persistent data path of the application on the user device. +The name of the Trackable in the World Storage must correspond to the name of a file (jpg or png) placed in the Unity persistent data path of the application on the user device. The variable keyvalueTags of the Trackable can also contain a parameter with the "url" key providing a link to download the image. More information about ARFoundation Image Tracking can be found here: https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/index.html ### Mesh Trackables ### -Mesh trackable are supported on iOS through ARKit. +Mesh trackables are supported on iOS through ARKit. -ARKit can track meshes that are defined in the .arobject format. Such an object can be scanned with the sample application provided here : https://developer.apple.com/documentation/arkit/arkit_in_ios/content_anchors/scanning_and_detecting_3d_objects +ARKit can track meshes that are defined in the .arobject format. Such an object can be scanned with the sample application provided here: https://developer.apple.com/documentation/arkit/arkit_in_ios/content_anchors/scanning_and_detecting_3d_objects Unity serializes .arobject into ARKitReferenceObjectEntry in the editor. ARKitReferenceObjectEntry cannot then be imported at runtime from a .arobjject file. Dynamic loading is not supported yet. diff --git a/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs new file mode 100644 index 0000000..d1b128c --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs @@ -0,0 +1,47 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Threading.Tasks; +using System.Net ; +using System.IO ; + +public class WorldAnalysisARFoundationHelper +{ + /// + /// Downaload file http + /// + /// load url + /// key and value with local path and file name with extension + public static async Task > DownloadFileHTTP(string toLoad) + { + string filePath = ""; + string fileName = ""; + #if UNITY_EDITOR + string folder = Application.streamingAssetsPath; + #else + string folder = Application.persistentDataPath; + #endif + + using (var client = new WebClient()) + { + await client.DownloadFileTaskAsync(toLoad, folder + "/Temp.data"); + string header_contentDisposition = client.ResponseHeaders["content-disposition"]; + if (header_contentDisposition == null) + { + string[] splittedLink = toLoad.Split('/'); + fileName = splittedLink[splittedLink.Length - 1]; + } + else + { + fileName = new System.Net.Mime.ContentDisposition(header_contentDisposition).FileName; + } + filePath = folder + "/" + fileName; + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + File.Move(folder + "/Temp.data", filePath); + } + return new KeyValuePair(filePath , fileName); + } +} diff --git a/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs.meta new file mode 100644 index 0000000..5602d29 --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7db7bb6556864f8a99c9e7d104f85df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs index 4908f8b..60c1865 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs @@ -68,7 +68,20 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod { return false; } - bool resul = AddImageToLibrary(trackable.Name, (float)trackable.TrackableSize[0]); + + // Check if an image url is provided + string url = "" ; + if (trackable.KeyvalueTags.ContainsKey("url")) + { + foreach(string s in trackable.KeyvalueTags["url"]) + { + // first one + url = s ; + break ; + } + } + + bool resul = AddImageToLibrary(trackable.Name, url, (float)trackable.TrackableSize[0]); if (resul) { m_uuidToName[trackable.UUID] = trackable.Name; @@ -133,9 +146,10 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod /// Add a new image to the arfoundation library /// /// file name + /// potential url /// image width in meters - /// - protected bool AddImageToLibrary(string fileName, float imageWidthInMeters) + /// image found or not + protected bool AddImageToLibrary(string fileName, string url, float imageWidthInMeters) { // check if image is in the library if (m_trackedImageInLibrary.Contains(fileName)) @@ -150,18 +164,50 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod #endif bool found = CheckImageExist(ref imagePath); // try to find in jpg or png - if (!found) + if (!found && url.Length == 0) { Debug.LogWarning("Try to Track Image " + fileName + " but file not found"); return false; } - - //Load texture and add it to arfoundation library + + if (!found) + { + // Here we don't check if url exists and still return true: could be improve + LoadTextureFromURL(url, fileName, imageWidthInMeters); + } + else + { + //Load texture and add it to arfoundation library + LoadTextureFromMemory(imagePath, fileName, imageWidthInMeters); + } + return true; + } + + /// + /// Add a new image from local memory to the arfoundation library + /// + /// local image path + /// file name + /// image width in meters + private void LoadTextureFromMemory(string imagePath, string fileName, float imageWidthInMeters) + { var rawData = File.ReadAllBytes(imagePath); Texture2D tex = new Texture2D(2, 2); tex.LoadImage(rawData); AddTextureToLibrary(tex, fileName, imageWidthInMeters); - return true; + } + + /// + /// Add a new image from a given url to the arfoundation library + /// + /// url to the image to download + /// file name + /// image width in meters + public async void LoadTextureFromURL(string url, string fileName, float imageWidthInMeters) + { + Debug.Log("Download image from url "+ url); + KeyValuePair downloaded = await WorldAnalysisARFoundationHelper.DownloadFileHTTP(url); + LoadTextureFromMemory(downloaded.Key, fileName, imageWidthInMeters); } /// -- GitLab From e02fee326ba02a276394577f8e5b6e2d7ef42665 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Wed, 26 Jun 2024 09:48:02 +0200 Subject: [PATCH 05/21] File download safe multiple download at the same time, prevent images from the same url to be downloaded several times --- .../Scripts/WorldAnalysisARFoundationHelper.cs | 11 ++++++----- .../WorldAnalysisARFoundationModuleImage.cs | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs index d1b128c..f3bb177 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationHelper.cs @@ -18,13 +18,14 @@ public class WorldAnalysisARFoundationHelper string fileName = ""; #if UNITY_EDITOR string folder = Application.streamingAssetsPath; - #else +#else string folder = Application.persistentDataPath; - #endif - +#endif + + string uniqueFileName = "/Temp"+ System.Guid.NewGuid()+".data"; using (var client = new WebClient()) { - await client.DownloadFileTaskAsync(toLoad, folder + "/Temp.data"); + await client.DownloadFileTaskAsync(toLoad, folder + uniqueFileName); string header_contentDisposition = client.ResponseHeaders["content-disposition"]; if (header_contentDisposition == null) { @@ -40,7 +41,7 @@ public class WorldAnalysisARFoundationHelper { File.Delete(filePath); } - File.Move(folder + "/Temp.data", filePath); + File.Move(folder + uniqueFileName, filePath); } return new KeyValuePair(filePath , fileName); } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs index 60c1865..bba58d8 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs @@ -17,7 +17,11 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod /// /// Name of all images that have been added to the library /// - private List m_trackedImageInLibrary; + private List m_trackedImageInLibrary; + /// + /// All url of images that have allready been downloaded + /// + private List m_allDownloadedImages; /// /// List of tracked images with tracking infos /// @@ -35,6 +39,7 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); m_trackedImageManager = origin.gameObject.AddComponent(); m_trackedImageInLibrary = new List(); + m_allDownloadedImages = new List(); m_trackedImageManager.trackedImagePrefab = (GameObject)Resources.Load("ARFImageTrackingPrefab"); m_trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged; } @@ -172,8 +177,12 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod if (!found) { - // Here we don't check if url exists and still return true: could be improve - LoadTextureFromURL(url, fileName, imageWidthInMeters); + // Do not download the same image twice + if (!m_allDownloadedImages.Contains(url)) + { + // Here we don't check if url exists and still return true: could be improve + LoadTextureFromURL(url, fileName, imageWidthInMeters); + } } else { @@ -206,6 +215,7 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod public async void LoadTextureFromURL(string url, string fileName, float imageWidthInMeters) { Debug.Log("Download image from url "+ url); + m_allDownloadedImages.Add(url); KeyValuePair downloaded = await WorldAnalysisARFoundationHelper.DownloadFileHTTP(url); LoadTextureFromMemory(downloaded.Key, fileName, imageWidthInMeters); } -- GitLab From c273ed9f691f0e8d79290b83de4cebe30a243a93 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Wed, 26 Jun 2024 17:20:57 +0200 Subject: [PATCH 06/21] Add possibility to use AssetBundle from a given url for mesh tracking --- README.md | 7 ++- .../WorldAnalysisARFoundationModuleMesh.cs | 62 ++++++++++++++----- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 497c9e5..a243148 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,14 @@ ARKit can track meshes that are defined in the .arobject format. Such an object Unity serializes .arobject into ARKitReferenceObjectEntry in the editor. ARKitReferenceObjectEntry cannot then be imported at runtime from a .arobjject file. Dynamic loading is not supported yet. -To support adding .arobject without recompiling the full application, we use a dedicated AssetBundle (named "arfmeshes"). To do so: +To support adding .arobject without recompiling the full application, we use a dedicated AssetBundle. * Place you .arobject in the Assets Folder. For instance under Assets/ARObjects * Associate the ARKitReferenceObjectEntry with the arfmeshes AssetBundle in the editor * Build the AssetBundles. For that you can use the following menu: ARF--> Build AssetBundles iOS -* Pace the "arfmeshes" file in the Unity persistent data path of the application on the user device. + +Then you have two options: +* Placing the AssetBundle "arfmeshes" file (with this exact file name) in the Unity persistent data path of the application on the user device. +* The variable keyvalueTags of the Trackable can also contain a parameter with the "url" key providing a link to download the AssetBundle to the Unity persistent data path on the user device. Only one AssetBundle can be loaded. The name of the Trackable in the World Storage must correspond to the name of the ARKitReferenceObjectEntry. diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs index 8b85e15..81862ec 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleMesh.cs @@ -17,7 +17,11 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu /// /// Name of all meshes that have been added to the library /// - private List m_trackedMeshesInLibrary; + private List m_trackedMeshesInLibrary; + /// + /// Has downloaded asset bundle from an url + /// + private bool m_hasDownloadedBundle; /// /// List of tracked meshses with tracking infos /// @@ -45,17 +49,7 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu m_trackedObjectManager.trackedObjectsChanged += OnTrackedMeshesChanged; m_trackedObjectManager.enabled = true ; // when instantiated without library : it is disabled m_entries = null; - - #if UNITY_EDITOR - string bundlePath = Application.streamingAssetsPath + "/arfmeshes" ; - #else - string bundlePath = Application.persistentDataPath + "/arfmeshes" ; - #endif - if (System.IO.File.Exists(bundlePath)) - { - AssetBundle bu = AssetBundle.LoadFromFile(bundlePath); - m_entries = bu.LoadAllAssets() ; - } + m_hasDownloadedBundle = false; } /// @@ -87,7 +81,20 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu { return false; } - bool resul = AddMeshToLibrary(trackable.Name) ;// (float)trackable.TrackableSize[0]); + + // Check if an AssetBundle url is provided + string url = ""; + if (trackable.KeyvalueTags.ContainsKey("url")) + { + foreach (string s in trackable.KeyvalueTags["url"]) + { + // first one + url = s; + break; + } + } + + bool resul = AddMeshToLibrary(trackable.Name , url) ;// (float)trackable.TrackableSize[0]); if (resul) { m_uuidToName[trackable.UUID] = trackable.Name; @@ -96,7 +103,7 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu } /// - /// Initialize capability object with image tracking + /// Initialize capability object with Mesh tracking /// public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() { @@ -153,7 +160,7 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu /// /// file name /// - protected bool AddMeshToLibrary(string fileName) + protected bool AddMeshToLibrary(string fileName, string url) { // check if mesh is in the library if (m_trackedMeshesInLibrary.Contains(fileName)) @@ -164,8 +171,29 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu if (m_entries == null) { - Debug.LogWarning("Try to Track Mesh but ARF Bundle with meshes is null"); - return false ; + +#if UNITY_EDITOR + string bundlePath = Application.streamingAssetsPath + "/arfmeshes"; +#else + string bundlePath = Application.persistentDataPath + "/arfmeshes" ; +#endif + + if (url.Length > 0 && !m_hasDownloadedBundle) + { + KeyValuePair download = System.Threading.Tasks.Task.Run(() => WorldAnalysisARFoundationHelper.DownloadFileHTTP(url)).Result; // synchronous : not perfect at all prevent to add another mesh while bundle is downloading + bundlePath = download.Key; + m_hasDownloadedBundle = true; + } + + if (System.IO.File.Exists(bundlePath)) + { + AssetBundle bu = AssetBundle.LoadFromFile(bundlePath); + m_entries = bu.LoadAllAssets(); + } + else + { + return false; + } } XRReferenceObjectEntry toAdd = null ; -- GitLab From 172068e0fdea526713b4f01c0b95ee0efc02d5a4 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Thu, 4 Jul 2024 18:18:08 +0200 Subject: [PATCH 07/21] First version ARCore Cloud Anchors --- Runtime/ARCoreExtensionsConfig.asset | 18 + Runtime/ARCoreExtensionsConfig.asset.meta | 8 + .../Resources/ARFAnchorTrackingPrefab.prefab | 435 ++++++++++++++++++ .../ARFAnchorTrackingPrefab.prefab.meta | 7 + Runtime/Scripts/WorldAnalysisARFoundation.cs | 11 +- ...orldAnalysisARFoundationCoroutineHelper.cs | 31 ++ ...nalysisARFoundationCoroutineHelper.cs.meta | 11 + ...dAnalysisARFoundationModuleARCoreAnchor.cs | 219 +++++++++ ...ysisARFoundationModuleARCoreAnchor.cs.meta | 11 + ...i.isg.arf.worldanalysisarfoundation.asmdef | 3 +- package.json | 15 +- 11 files changed, 758 insertions(+), 11 deletions(-) create mode 100644 Runtime/ARCoreExtensionsConfig.asset create mode 100644 Runtime/ARCoreExtensionsConfig.asset.meta create mode 100644 Runtime/Resources/ARFAnchorTrackingPrefab.prefab create mode 100644 Runtime/Resources/ARFAnchorTrackingPrefab.prefab.meta create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs.meta create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs.meta diff --git a/Runtime/ARCoreExtensionsConfig.asset b/Runtime/ARCoreExtensionsConfig.asset new file mode 100644 index 0000000..858be38 --- /dev/null +++ b/Runtime/ARCoreExtensionsConfig.asset @@ -0,0 +1,18 @@ +%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: 4ae147bac9ff8453284f59548528c2aa, type: 3} + m_Name: ARCoreExtensionsConfig + m_EditorClassIdentifier: + CloudAnchorMode: 1 + SemanticMode: 0 + GeospatialMode: 0 + StreetscapeGeometryMode: 0 diff --git a/Runtime/ARCoreExtensionsConfig.asset.meta b/Runtime/ARCoreExtensionsConfig.asset.meta new file mode 100644 index 0000000..69fdd40 --- /dev/null +++ b/Runtime/ARCoreExtensionsConfig.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf9adc83079e8e1479b1a105856aab0e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab new file mode 100644 index 0000000..4b74c4b --- /dev/null +++ b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab @@ -0,0 +1,435 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6911754431728604848 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754431728604849} + m_Layer: 0 + m_Name: ARFAnchorTrackingPrefab + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754431728604849 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754431728604848} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6911754432812775763} + - {fileID: 6911754433267149346} + - {fileID: 6911754433204531549} + - {fileID: 5348077246929615354} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6911754432812775762 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754432812775763} + - component: {fileID: 6911754432812775758} + - component: {fileID: 6911754432812775757} + - component: {fileID: 6911754432812775756} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754432812775763 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.0701} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11557999} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6911754432812775758 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754432812775757 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9fd9c0bd2f4f1438888297d0668f871b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754432812775756 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754432812775762} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433204531548 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433204531549} + - component: {fileID: 6911754433204531544} + - component: {fileID: 6911754433204531551} + - component: {fileID: 6911754433204531550} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433204531549 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + serializedVersion: 2 + m_LocalRotation: {x: -0.5, y: -0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.0525, z: 0.0033} + m_LocalScale: {x: 0.0100000035, y: 0.01, z: 0.11558006} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: -90, y: -90.00001, z: 0} +--- !u!33 &6911754433204531544 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433204531551 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: de76e3ad692ba4492aaca3dd54e65f04, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433204531550 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433204531548} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &6911754433267149345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6911754433267149346} + - component: {fileID: 6911754433267149341} + - component: {fileID: 6911754433267149340} + - component: {fileID: 6911754433267149347} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6911754433267149346 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: -0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.0528, y: 0, z: 0.0033} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.11558} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: -90, z: 0} +--- !u!33 &6911754433267149341 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6911754433267149340 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9d815ae4d5a7b46ae99e4e5ed084d3a8, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &6911754433267149347 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6911754433267149345} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &7290371484074973697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5348077246929615354} + - component: {fileID: 3993039649644943769} + - component: {fileID: 5219444789236537599} + m_Layer: 0 + m_Name: Cylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5348077246929615354 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7290371484074973697} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.025, y: 0.025, z: 0.025} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3993039649644943769 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7290371484074973697} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5219444789236537599 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7290371484074973697} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab.meta b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab.meta new file mode 100644 index 0000000..b7050cb --- /dev/null +++ b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e5177a22bf3f76943a9c36a96126aaf5 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index bd82b85..671265f 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -69,6 +69,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface protected void Awake() { Instance = this; + this.gameObject.AddComponent(); m_relocalizationInformations = new Dictionary(); m_computedPoses = new Dictionary(); m_subscriptionsPoses = new Dictionary(); @@ -76,10 +77,16 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface m_trackableModules = new List(); WorldAnalysisARFoundationModuleImage imageModule = new WorldAnalysisARFoundationModuleImage(); m_trackableModules.Add(imageModule); - #if UNITY_IOS +#if UNITY_IOS WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); m_trackableModules.Add(meshModule); - #endif +#endif +#if UNITY_ANDROID + // todo add script define symbol for using arcore extensions + WorldAnalysisARFoundationModuleARCoreAnchor arCoreAnchorModule = new WorldAnalysisARFoundationModuleARCoreAnchor(); + m_trackableModules.Add(arCoreAnchorModule); +#endif + foreach(WorldAnalysisARFoundationModule module in m_trackableModules) { module.Initialize(); diff --git a/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs new file mode 100644 index 0000000..2aebd07 --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs @@ -0,0 +1,31 @@ +using System.Collections; +using UnityEngine; + +public class WorldAnalysisARFoundationCoroutineHelper : MonoBehaviour +{ + //Singleton + public static WorldAnalysisARFoundationCoroutineHelper Instance { get; private set; } + + private void Awake() + { + // If there is an instance, and it's not me, delete myself. + + + Debug.Log("HERE SINGLETON AWAKE"); + + if (Instance != null && Instance != this) + { + Destroy(this); + } + else + { + Instance = this; + } + } + + public void StartACoroutine(IEnumerator coroutine) + { + Debug.Log("HERE SINGLETON"); + StartCoroutine(coroutine); + } +} diff --git a/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs.meta new file mode 100644 index 0000000..9d9455d --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bba8c444e6fa865469446e417be28e45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs new file mode 100644 index 0000000..4ef7bc9 --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -0,0 +1,219 @@ +#if UNITY_ANDROID +using System; +using System.Collections; +using System.Collections.Generic; +using Google.XR.ARCoreExtensions; +using Unity.XR.CoreUtils; +using UnityEngine; +using UnityEngine.XR.ARFoundation; +using UnityEngine.XR.ARSubsystems; +using static WorldAnalysisARFoundationModule; + +public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFoundationModule +{ + /// + /// + /// + private ARAnchorManager m_anchorManager; + /// + /// IDs of all the cloud anchors that have been resolved + /// + private List m_cloudAnchorAdded;//useful ? + /// + /// List of cloud anchors with tracking infos + /// + private Dictionary m_trackedCloudAnchors = new Dictionary(); + /// + /// + /// + private List _resolvePromises = new List(); + /// + /// + /// + private List _resolveResults = new List(); + /// + /// Correspondance between google cloud id and local trackable id + /// + private Dictionary m_localIdToCloudId = new Dictionary(); + + /// + /// ETSI ID + /// + private Dictionary m_CloudIdToETSIId = new Dictionary(); + + /// + /// + /// + private GameObject m_anchorPrefab; + + /// + /// Initialize ARCore cloud anchors tracking module + /// + public void Initialize() + { + XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); + m_anchorManager = origin.gameObject.AddComponent(); + m_cloudAnchorAdded = new List(); + m_anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); + m_anchorManager.anchorPrefab = m_anchorPrefab; + m_anchorManager.anchorsChanged += OnTrackedCloudAnchorChanged; + } + + /// + /// + /// + /// + /// + public TrackableInfo GetPoseTrackable(Guid uuid) + { + if (m_trackedCloudAnchors.ContainsKey(uuid.ToString())) + { + return m_trackedCloudAnchors[uuid.ToString()]; + } + else + { + return null; + } + } + + /// + /// + /// + /// + /// + public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) + { + /// Here : we don't check if the trackable is allready added, AddImageToLibrary does it + if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.MAP) + { + return false; + } + AddNewARCoreCloudAnchor(trackable); + return true; + } + + /// + /// + /// + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() + { + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityARCoreAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityARCoreAnchor.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARCORE; + encodingInformation.Version = "1.01"; + capabilityARCoreAnchor.EncodingInformation = encodingInformation; + capabilityARCoreAnchor.Framerate = 30; // Not particularly specified on ARKit and ARCore + capabilityARCoreAnchor.Latency = 0; // Not particularly specified on ARKit and ARCore + capabilityARCoreAnchor.Accuracy = 1; // Not particularly specified on ARKit and ARCore + return capabilityARCoreAnchor; + } + + /// + /// + /// + /// + private void OnTrackedCloudAnchorChanged(ARAnchorsChangedEventArgs eventArgs) + { + foreach (var trackedCloudAnchor in eventArgs.updated) + { + Vector3 position = trackedCloudAnchor.transform.position; + Quaternion rotation = trackedCloudAnchor.transform.rotation; + + + TrackableInfo info = new TrackableInfo(); + info.name = trackedCloudAnchor.name; + string localId = trackedCloudAnchor.trackableId.subId1.ToString("X16");// there must be a better way : does it work every time? + if (m_localIdToCloudId.ContainsKey(localId)) + { + info.name = m_CloudIdToETSIId[m_localIdToCloudId[localId]]; + } + else + { + Debug.Log("ARCore Cloud Anchor No correspondance for Local Anchor " + localId); + continue; + } + + if (trackedCloudAnchor.trackingState == TrackingState.Tracking) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 100; + } + else if (trackedCloudAnchor.trackingState == TrackingState.Limited) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 50; + } + else + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.FAILURE; //ADD NOT_TRACKED ? + info.confidence = 0; + } + info.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + info.position = position; + info.rotation = rotation; + info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.IMAGE_MARKER; + m_trackedCloudAnchors[info.name] = info; + } + } + + /// + /// + /// + /// + private async void AddNewARCoreCloudAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable ) + { + while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None ||ARSession.state == ARSessionState.SessionInitializing) + { + await System.Threading.Tasks.Task.Delay(100); + } + string googleCloudID = trackable.Name; + m_CloudIdToETSIId.Add(googleCloudID, trackable.UUID.ToString()); + ResolveCloudAnchor(googleCloudID); + } + + /// + /// Resolves Cloud Anchors using a given id + /// + /// + public void ResolveCloudAnchor(string cloudId) + { + var promise = m_anchorManager.ResolveCloudAnchorAsync(cloudId); + if (promise.State == PromiseState.Done) + { + Debug.LogFormat("Failed to resolve Cloud Anchor " + cloudId); + } + else + { + _resolvePromises.Add(promise); + var coroutine = ResolveAnchor(promise, cloudId); + WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine); + } + } + + /// + /// + /// + /// + /// + private IEnumerator ResolveAnchor(ResolveCloudAnchorPromise promise, string cloudId) + { + yield return promise; + var result = promise.Result; + _resolvePromises.Remove(promise); + _resolveResults.Add(result); + + if (result.CloudAnchorState == CloudAnchorState.Success) + { + Debug.Log("ARCloud Anchor Resolve Sucess" +cloudId); + m_localIdToCloudId.Add(result.Anchor.trackableId.subId2.ToString("X16"), cloudId); // should be a better way: not sure about that but subId2 of the ARCloudAnchor seems to correspond to subId1 of local anchor that is updated by Anchor Manager + } + else + { + Debug.Log("ARCloud Anchor Resolve Failed" + result.CloudAnchorState + " " +cloudId); + } + } +} + +#endif \ No newline at end of file diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs.meta new file mode 100644 index 0000000..9e979e9 --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2cec98c043216c94db7d09c20b3cce67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef b/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef index 80bdd36..8a0ef7e 100644 --- a/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef +++ b/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef @@ -6,7 +6,8 @@ "GUID:065e856e9f9becb49abdf0cb6855a039", "GUID:a9420e37d7990b54abdef6688edbe313", "GUID:92703082f92b41ba80f0d6912de66115", - "GUID:dc960734dc080426fa6612f1c5fe95f3" + "GUID:dc960734dc080426fa6612f1c5fe95f3", + "GUID:b35d8248e1a04478bb2d70fe76652ddf" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/package.json b/package.json index ff8e8c7..57ef95e 100644 --- a/package.json +++ b/package.json @@ -2,16 +2,15 @@ "author": "ETSI-ISG-ARF", "name": "etsi.isg.arf.worldanalysisarfoundation", "version": "0.0.1", - "displayName": "ISG-ARF World Analysis ARFoundation Wrapper Package ", + "displayName": "ISG-ARF World Analysis ARFoundation Wrapper Package", "description": "ARFoundation wrapper for the World Analysis of the Augmented Reality Framework", "unity": "2021.3", "dependencies": { - "etsi.isg.arf.worldstorage" : "0.0.2", - "etsi.isg.arf.worldanalysis" : "0.0.1", - "com.unity.xr.arfoundation": "5.1.3", - "com.unity.xr.arkit": "5.1.3", - "com.unity.xr.arcore": "5.1.3" - - }, + "etsi.isg.arf.worldstorage": "0.0.2", + "etsi.isg.arf.worldanalysis": "0.0.1", + "com.unity.xr.arfoundation": "5.1.3", + "com.unity.xr.arkit": "5.1.3", + "com.unity.xr.arcore": "5.1.3" + }, "keywords": [] } \ No newline at end of file -- GitLab From e68c91f304caf48e3221e71a06fd2fc834e4b19b Mon Sep 17 00:00:00 2001 From: jlacoche Date: Fri, 5 Jul 2024 09:58:58 +0200 Subject: [PATCH 08/21] simplify arcore anchor module and remove arcoreextensions on ios --- Runtime/Scripts/WorldAnalysisARFoundation.cs | 13 ++++- ...dAnalysisARFoundationModuleARCoreAnchor.cs | 58 +++++-------------- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 671265f..9562f7b 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -8,6 +8,7 @@ using System.Collections; using System.Linq; using ETSI.ARF.OpenAPI.WorldStorage; using ETSI.ARF.WorldStorage.REST; +using ; //Implementation of the WorldAnalysis interface public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface @@ -81,13 +82,23 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); m_trackableModules.Add(meshModule); #endif +#if ETSIARF_ARCORE_EXTENSIONS + #if UNITY_ANDROID // todo add script define symbol for using arcore extensions WorldAnalysisARFoundationModuleARCoreAnchor arCoreAnchorModule = new WorldAnalysisARFoundationModuleARCoreAnchor(); m_trackableModules.Add(arCoreAnchorModule); +#else + /// on other os : if arcore extensions is in the scene we disable it + Google.XR.ARCoreExtensions.ARCoreExtensions arCoreExtensions = Component.FindObjectOfType(); + if (arCoreExtensions != null) + { + arCoreExtensions.enabled = false; + } +#endif #endif - foreach(WorldAnalysisARFoundationModule module in m_trackableModules) + foreach (WorldAnalysisARFoundationModule module in m_trackableModules) { module.Initialize(); } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs index 4ef7bc9..9bd2d3e 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -1,4 +1,4 @@ -#if UNITY_ANDROID +#if UNITY_ANDROID && ETSIARF_ARCORE_EXTENSIONS using System; using System.Collections; using System.Collections.Generic; @@ -12,39 +12,17 @@ using static WorldAnalysisARFoundationModule; public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFoundationModule { /// - /// + /// Anchor manager /// private ARAnchorManager m_anchorManager; /// - /// IDs of all the cloud anchors that have been resolved - /// - private List m_cloudAnchorAdded;//useful ? - /// /// List of cloud anchors with tracking infos /// private Dictionary m_trackedCloudAnchors = new Dictionary(); /// - /// - /// - private List _resolvePromises = new List(); - /// - /// - /// - private List _resolveResults = new List(); - /// - /// Correspondance between google cloud id and local trackable id + /// Correspondance between local trackable and etsi uuid /// - private Dictionary m_localIdToCloudId = new Dictionary(); - - /// - /// ETSI ID - /// - private Dictionary m_CloudIdToETSIId = new Dictionary(); - - /// - /// - /// - private GameObject m_anchorPrefab; + private Dictionary m_localIdToEtsiId = new Dictionary(); /// /// Initialize ARCore cloud anchors tracking module @@ -53,9 +31,8 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda { XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); m_anchorManager = origin.gameObject.AddComponent(); - m_cloudAnchorAdded = new List(); - m_anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); - m_anchorManager.anchorPrefab = m_anchorPrefab; + GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); + m_anchorManager.anchorPrefab = anchorPrefab; m_anchorManager.anchorsChanged += OnTrackedCloudAnchorChanged; } @@ -88,7 +65,7 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda { return false; } - AddNewARCoreCloudAnchor(trackable); + AddNewARCoreCloudAnchor(trackable); // here we don't check if the cloud anchor is correctly resolved, this could be imrpoved but would require this method to be async (change of api) return true; } @@ -125,9 +102,9 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda TrackableInfo info = new TrackableInfo(); info.name = trackedCloudAnchor.name; string localId = trackedCloudAnchor.trackableId.subId1.ToString("X16");// there must be a better way : does it work every time? - if (m_localIdToCloudId.ContainsKey(localId)) + if (m_localIdToEtsiId.ContainsKey(localId)) { - info.name = m_CloudIdToETSIId[m_localIdToCloudId[localId]]; + info.name = m_localIdToEtsiId[localId]; } else { @@ -169,25 +146,23 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda await System.Threading.Tasks.Task.Delay(100); } string googleCloudID = trackable.Name; - m_CloudIdToETSIId.Add(googleCloudID, trackable.UUID.ToString()); - ResolveCloudAnchor(googleCloudID); + ResolveCloudAnchor(googleCloudID, trackable.UUID.ToString()); } /// /// Resolves Cloud Anchors using a given id /// /// - public void ResolveCloudAnchor(string cloudId) + public void ResolveCloudAnchor(string cloudId, string etsiId) { var promise = m_anchorManager.ResolveCloudAnchorAsync(cloudId); if (promise.State == PromiseState.Done) { - Debug.LogFormat("Failed to resolve Cloud Anchor " + cloudId); + Debug.Log("Failed to resolve Cloud Anchor " + cloudId); } else { - _resolvePromises.Add(promise); - var coroutine = ResolveAnchor(promise, cloudId); + var coroutine = ResolveAnchor(promise, cloudId, etsiId); WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine); } } @@ -197,17 +172,14 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda /// /// /// - private IEnumerator ResolveAnchor(ResolveCloudAnchorPromise promise, string cloudId) + private IEnumerator ResolveAnchor(ResolveCloudAnchorPromise promise, string cloudId, string etsiId) { yield return promise; var result = promise.Result; - _resolvePromises.Remove(promise); - _resolveResults.Add(result); - if (result.CloudAnchorState == CloudAnchorState.Success) { Debug.Log("ARCloud Anchor Resolve Sucess" +cloudId); - m_localIdToCloudId.Add(result.Anchor.trackableId.subId2.ToString("X16"), cloudId); // should be a better way: not sure about that but subId2 of the ARCloudAnchor seems to correspond to subId1 of local anchor that is updated by Anchor Manager + m_localIdToEtsiId.Add(result.Anchor.trackableId.subId2.ToString("X16"), etsiId); // should be a better way: not sure about that but subId2 of the ARCloudAnchor seems to correspond to subId1 of local anchor that is updated by Anchor Manager } else { -- GitLab From 5ca2a94b762be71f1f16d70991e3174247da6529 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Fri, 5 Jul 2024 10:02:42 +0200 Subject: [PATCH 09/21] fix compilation error... --- Runtime/Scripts/WorldAnalysisARFoundation.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 9562f7b..02484a7 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -8,7 +8,6 @@ using System.Collections; using System.Linq; using ETSI.ARF.OpenAPI.WorldStorage; using ETSI.ARF.WorldStorage.REST; -using ; //Implementation of the WorldAnalysis interface public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface -- GitLab From 900e2250f8d8b9eaa2514fac3818d7d41213f84d Mon Sep 17 00:00:00 2001 From: jlacoche Date: Sat, 6 Jul 2024 00:35:24 +0200 Subject: [PATCH 10/21] Add module for arkit world map --- Runtime/Scripts/WorldAnalysisARFoundation.cs | 2 + ...dAnalysisARFoundationModuleARCoreAnchor.cs | 12 +- ...AnalysisARFoundationModuleARKitWorldMap.cs | 221 ++++++++++++++++++ ...sisARFoundationModuleARKitWorldMap.cs.meta | 11 + .../WorldAnalysisARFoundationModuleImage.cs | 2 +- ...i.isg.arf.worldanalysisarfoundation.asmdef | 3 +- 6 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs.meta diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 02484a7..055a72d 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -80,6 +80,8 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface #if UNITY_IOS WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); m_trackableModules.Add(meshModule); + WorldAnalysisARFoundationModuleARKitWorldMap worldMapModule = new WorldAnalysisARFoundationModuleARKitWorldMap(); + m_trackableModules.Add(worldMapModule); #endif #if ETSIARF_ARCORE_EXTENSIONS diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs index 9bd2d3e..f593e41 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -37,10 +37,10 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Get the pose of the trackable from its uuid /// - /// - /// + /// id of the trackable + /// null or trackableInfo with last updated values public TrackableInfo GetPoseTrackable(Guid uuid) { if (m_trackedCloudAnchors.ContainsKey(uuid.ToString())) @@ -54,10 +54,10 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Need to be a map /// /// - /// + /// map or not (does not check is solved) public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { /// Here : we don't check if the trackable is allready added, AddImageToLibrary does it @@ -130,7 +130,7 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda info.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); info.position = position; info.rotation = rotation; - info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.IMAGE_MARKER; + info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP; m_trackedCloudAnchors[info.name] = info; } } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs new file mode 100644 index 0000000..5bb1ea4 --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs @@ -0,0 +1,221 @@ + +#if UNITY_IOS +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.XR.ARFoundation; +using UnityEngine.XR.ARSubsystems; +using UnityEngine.XR.ARKit; +using System.IO; +using Unity.XR.CoreUtils; +using static WorldAnalysisARFoundationModule; +using ETSI.ARF.OpenAPI.WorldStorage; +using Unity.Collections; + + +public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFoundationModule +{ + /// + /// Anchor manager + /// + private ARAnchorManager m_anchorManager; + ///Has loaded a worl map + private bool m_hasAddedMap ; + /// Possible trackable id (arfoundation) of an anchor contained in the world map. Take the pose of this anchor if it exists or zero + private string m_arfoundationAnchorTrackableId ; + /// uuId of the map trackabled + private Guid m_trackedUUID ; + /// computed and updated pose + private TrackableInfo m_trackedPose ; + + /// + /// Initialize image tracking module + /// + public void Initialize() + { + XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); + m_anchorManager = origin.gameObject.AddComponent(); + GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); + m_anchorManager.anchorPrefab = anchorPrefab; + m_anchorManager.anchorsChanged += OnTrackedAnchorChanged; + m_trackedPose = null ; + m_hasAddedMap= false ; + } + + /// + /// found + /// + /// name of the mesh trackable + public TrackableInfo GetPoseTrackable(Guid uuid) + { + if (m_trackedPose != null) + { + if (m_trackedUUID == uuid) + { + return m_trackedPose ; + } + } + return null; + } + + /// + /// Add a trackable : need to be a map + /// + /// Image trackable + /// Supported or not + public bool AddTrackable(Trackable trackable) + { + if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.MAP) + { + return false; + } + if (m_hasAddedMap) + { + Debug.Log("Only one ARKit map can be loaded"); + return false ; + } + + // Check if a map url is provided + string url = "" ; + if (trackable.KeyvalueTags.ContainsKey("url")) + { + foreach(string s in trackable.KeyvalueTags["url"]) + { + // first one + url = s ; + break ; + } + } + bool resul = AddWorldMapToARKit(url); + m_trackedUUID = trackable.UUID ; + m_arfoundationAnchorTrackableId = trackable.Name ; + m_hasAddedMap = resul ; + return resul; + } + + /// + /// Initialize capability object with Mesh tracking + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() + { + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityMesh = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityMesh.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARKIT; + encodingInformation.Version = "1.01"; + capabilityMesh.EncodingInformation = encodingInformation; + capabilityMesh.Framerate = 30; // Not particularly specified on ARKit + capabilityMesh.Latency = 0; // Not particularly specified on ARKit + capabilityMesh.Accuracy = 1; // Not particularly specified on ARKit + return capabilityMesh ; + } + + /// + /// Callback when Unity anchors are updated + /// + /// update values + private void OnTrackedAnchorChanged(ARAnchorsChangedEventArgs eventArgs) + { + foreach (var trackedAnchor in eventArgs.updated) + { + if (trackedAnchor.trackableId.ToString() == m_arfoundationAnchorTrackableId) + { + /// look for an anchor with the trackable Id correspond to the ETSI ARF trackable name + UpdateTrackableInfoWithPose(trackedAnchor.transform.position,trackedAnchor.transform.rotation); + break ; + } + } + } + + /// + /// Add a map to arkitsubsystem : check local file exist or download from given url + /// + /// url of a map to download + /// found or not + protected bool AddWorldMapToARKit(string url) + { + if (url.Length > 0) + { + LoadWorldMapFromURL(url); + // don't check if url is valid + return true ; + } + else + { + string localMap = Application.persistentDataPath + "/ARkitWorlMap.map"; + if (File.Exists(localMap)) + { + var coroutine = CoroutineLoadWorldMap(localMap); + WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine); + return true ; + } + } + // no url and no local map + return false ; + } + + /// + /// Update pose of the map trackable + /// + /// evaluated position of trackable/param> + /// evaluated rotation of the trackable + private void UpdateTrackableInfoWithPose(Vector3 position, Quaternion rotation) + { + m_trackedPose = new TrackableInfo(); + m_trackedPose.name = m_arfoundationAnchorTrackableId; + m_trackedPose.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; // here : could check the state of the ARKit slam + m_trackedPose.confidence = 100; + m_trackedPose.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + m_trackedPose.position = position; + m_trackedPose.rotation = rotation; + m_trackedPose.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP; + } + + /// + /// Load a world map from a url + /// + /// url to the worlmap to download + private async void LoadWorldMapFromURL(string url) + { + Debug.Log("Download WorlMap from url "+ url); + KeyValuePair downloaded = await WorldAnalysisARFoundationHelper.DownloadFileHTTP(url); + var coroutine = CoroutineLoadWorldMap(downloaded.Key); + WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine); + } + + /// + /// Load current map from path + /// + /// path of the map + /// coroutine + public IEnumerator CoroutineLoadWorldMap(string mapPath) + { + ARSession session = Component.FindAnyObjectByType() ; + ARKitSessionSubsystem sessionSubsystem = (ARKitSessionSubsystem)session.subsystem; + FileStream file; + file = File.Open(mapPath, FileMode.Open); + const int bytesPerFrame = 1024 * 10; + var bytesRemaining = file.Length; + var binaryReader = new BinaryReader(file); + var allBytes = new List(); + while (bytesRemaining > 0) + { + var bytes = binaryReader.ReadBytes(bytesPerFrame); + allBytes.AddRange(bytes); + bytesRemaining -= bytesPerFrame; + yield return null; + } + + var data = new NativeArray(allBytes.Count, Allocator.Temp); + data.CopyFrom(allBytes.ToArray()); + ARWorldMap worldMap; + if (ARWorldMap.TryDeserialize(data, out worldMap)) + { + data.Dispose(); + } + sessionSubsystem.ApplyWorldMap(worldMap); + UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map + } +} +#endif \ No newline at end of file diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs.meta new file mode 100644 index 0000000..ac4deff --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0eb5e51c9f2ae4e8db0c43c245bf7b41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs index bba58d8..ab15c6e 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleImage.cs @@ -212,7 +212,7 @@ public class WorldAnalysisARFoundationModuleImage : WorldAnalysisARFoundationMod /// url to the image to download /// file name /// image width in meters - public async void LoadTextureFromURL(string url, string fileName, float imageWidthInMeters) + private async void LoadTextureFromURL(string url, string fileName, float imageWidthInMeters) { Debug.Log("Download image from url "+ url); m_allDownloadedImages.Add(url); diff --git a/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef b/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef index 8a0ef7e..6ce3bc4 100644 --- a/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef +++ b/Runtime/etsi.isg.arf.worldanalysisarfoundation.asmdef @@ -7,7 +7,8 @@ "GUID:a9420e37d7990b54abdef6688edbe313", "GUID:92703082f92b41ba80f0d6912de66115", "GUID:dc960734dc080426fa6612f1c5fe95f3", - "GUID:b35d8248e1a04478bb2d70fe76652ddf" + "GUID:b35d8248e1a04478bb2d70fe76652ddf", + "GUID:dfd0ce20189d48e5b22bb4134b558f5a" ], "includePlatforms": [], "excludePlatforms": [], -- GitLab From 608fce800a7a28a2351908d1c55fb00551eb6390 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Mon, 8 Jul 2024 11:29:25 +0200 Subject: [PATCH 11/21] remove some log, wait for arsession to be ready for loading arkit world map --- ...orldAnalysisARFoundationCoroutineHelper.cs | 8 +-- ...AnalysisARFoundationModuleARKitWorldMap.cs | 55 ++++++++++++------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs index 2aebd07..b240bde 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationCoroutineHelper.cs @@ -8,11 +8,6 @@ public class WorldAnalysisARFoundationCoroutineHelper : MonoBehaviour private void Awake() { - // If there is an instance, and it's not me, delete myself. - - - Debug.Log("HERE SINGLETON AWAKE"); - if (Instance != null && Instance != this) { Destroy(this); @@ -25,7 +20,6 @@ public class WorldAnalysisARFoundationCoroutineHelper : MonoBehaviour public void StartACoroutine(IEnumerator coroutine) { - Debug.Log("HERE SINGLETON"); StartCoroutine(coroutine); } -} +} \ No newline at end of file diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs index 5bb1ea4..5b1ef20 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs @@ -119,6 +119,8 @@ public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFound { foreach (var trackedAnchor in eventArgs.updated) { + Debug.Log("Anchor found " +trackedAnchor.trackableId.ToString()); + if (trackedAnchor.trackableId.ToString() == m_arfoundationAnchorTrackableId) { /// look for an anchor with the trackable Id correspond to the ETSI ARF trackable name @@ -137,12 +139,14 @@ public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFound { if (url.Length > 0) { + Debug.Log("Load AR Map from URL"); LoadWorldMapFromURL(url); // don't check if url is valid return true ; } else { + Debug.Log("Load AR Map locally"); string localMap = Application.persistentDataPath + "/ARkitWorlMap.map"; if (File.Exists(localMap)) { @@ -191,31 +195,44 @@ public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFound /// coroutine public IEnumerator CoroutineLoadWorldMap(string mapPath) { + while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None ||ARSession.state == ARSessionState.SessionInitializing) + { + // wait for ar session to be ready + yield return null ; + } + ARSession session = Component.FindAnyObjectByType() ; ARKitSessionSubsystem sessionSubsystem = (ARKitSessionSubsystem)session.subsystem; - FileStream file; - file = File.Open(mapPath, FileMode.Open); - const int bytesPerFrame = 1024 * 10; - var bytesRemaining = file.Length; - var binaryReader = new BinaryReader(file); - var allBytes = new List(); - while (bytesRemaining > 0) + if (sessionSubsystem == null) { - var bytes = binaryReader.ReadBytes(bytesPerFrame); - allBytes.AddRange(bytes); - bytesRemaining -= bytesPerFrame; - yield return null; + Debug.Log("Cannot load map: no ARKitSessionSubsystem"); } - - var data = new NativeArray(allBytes.Count, Allocator.Temp); - data.CopyFrom(allBytes.ToArray()); - ARWorldMap worldMap; - if (ARWorldMap.TryDeserialize(data, out worldMap)) + else { - data.Dispose(); + FileStream file; + file = File.Open(mapPath, FileMode.Open); + const int bytesPerFrame = 1024 * 10; + var bytesRemaining = file.Length; + var binaryReader = new BinaryReader(file); + var allBytes = new List(); + while (bytesRemaining > 0) + { + var bytes = binaryReader.ReadBytes(bytesPerFrame); + allBytes.AddRange(bytes); + bytesRemaining -= bytesPerFrame; + yield return null; + } + + var data = new NativeArray(allBytes.Count, Allocator.Temp); + data.CopyFrom(allBytes.ToArray()); + ARWorldMap worldMap; + if (ARWorldMap.TryDeserialize(data, out worldMap)) + { + data.Dispose(); + } + sessionSubsystem.ApplyWorldMap(worldMap); + UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map } - sessionSubsystem.ApplyWorldMap(worldMap); - UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map } } #endif \ No newline at end of file -- GitLab From 8f8b5503ed11b56ee378fd4a05e5974c9958d79b Mon Sep 17 00:00:00 2001 From: jlacoche Date: Mon, 8 Jul 2024 12:32:07 +0200 Subject: [PATCH 12/21] Update documentation for arkit maps --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index a243148..867129c 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,16 @@ The name of the Trackable in the World Storage must correspond to the name of th More information about ARFoundation Mesh Tracking can be found here: https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/features/object-tracking.html +### ARKit ARWorldMap ### +In ARKit, an ARWorldMap includes ARKit's awareness of the physical space in which the user moves the device that can be serialized into a file to be reloaded later on the same or on another device: +https://developer.apple.com/documentation/arkit/arworldmap +On iOS/ARKit Map Trackables are supported with this feature. Only one Map Trackable per World Graph is supported. + +The .map file can be placed in the Unity persistent data path of the application on the user device with the following name: "ARkitWorlMap.map". Alternatively, the variable keyvalueTags of the Trackable can also contain a parameter with the "url" key providing a link to download the map file. + +By default, the origin of the Map Trackable is the point (0, 0 ,0). If the Map includes an Anchor, you can use it as the origin by setting the name of the Trackable in the World Storage with the TrackableId of the ARAnchor stored in the map. https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/api/UnityEngine.XR.ARSubsystems.TrackableId.html + +Samples for creating ARWorldMap with ARFoundation can be found here: +https://github.com/Unity-Technologies/arfoundation-samples/blob/main/Assets/Scripts/Runtime/ARWorldMapController.cs \ No newline at end of file -- GitLab From 64114a03871dd7b3525492c0d58cc24f1cf049c0 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Mon, 8 Jul 2024 13:50:14 +0200 Subject: [PATCH 13/21] Add documentation for arcore cloud anchors, start documentation for geo trackables --- README.md | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 867129c..24c4251 100644 --- a/README.md +++ b/README.md @@ -49,16 +49,46 @@ The name of the Trackable in the World Storage must correspond to the name of th More information about ARFoundation Mesh Tracking can be found here: https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/manual/features/object-tracking.html -### ARKit ARWorldMap ### +### Map Trackables ### + +#### iOS: ARWorldMap #### + +On iOS/ARKit Map Trackables are supported with ARWorlMap feature. Only one Map Trackable per World Graph is supported. In ARKit, an ARWorldMap includes ARKit's awareness of the physical space in which the user moves the device that can be serialized into a file to be reloaded later on the same or on another device: https://developer.apple.com/documentation/arkit/arworldmap -On iOS/ARKit Map Trackables are supported with this feature. Only one Map Trackable per World Graph is supported. - The .map file can be placed in the Unity persistent data path of the application on the user device with the following name: "ARkitWorlMap.map". Alternatively, the variable keyvalueTags of the Trackable can also contain a parameter with the "url" key providing a link to download the map file. By default, the origin of the Map Trackable is the point (0, 0 ,0). If the Map includes an Anchor, you can use it as the origin by setting the name of the Trackable in the World Storage with the TrackableId of the ARAnchor stored in the map. https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/api/UnityEngine.XR.ARSubsystems.TrackableId.html -Samples for creating ARWorldMap with ARFoundation can be found here: -https://github.com/Unity-Technologies/arfoundation-samples/blob/main/Assets/Scripts/Runtime/ARWorldMapController.cs \ No newline at end of file +Samples for creating and serializing an ARWorldMap with ARFoundation can be found here: +https://github.com/Unity-Technologies/arfoundation-samples/blob/main/Assets/Scripts/Runtime/ARWorldMapController.cs + +#### Android ARCore Cloud Anchors #### + +On Android/ARcore Map Trackables are supported with Cloud Anchors. + +Cloud Anchors are anchors that are hosted on the ARCore API cloud endpoint. This hosting enables users to share experiences in the same app: see https://developers.google.com/ar/develop/cloud-anchors + +For using ARCore cloud anchors you need to: +* Add the the arcore unity extensions package as a dependency of the Unity project https://github.com/google-ar/arcore-unity-extensions +* Add to the runtime asmdef of this package a reference to Google.XR.ARCoreExtensions.asmdef +* Add a new Script Define Symbol in the Unity project settings: "ETSIARF_ARCORE_EXTENSIONS" +* Then, follow the instructions detailed here https://developers.google.com/ar/develop/unity-arf/cloud-anchors/developer-guide and here https://developers.google.com/ar/develop/authorization?platform=unity-arf to configure the project and your google cloud account + +To use a Map Trackable that corresponds to a Google Cloud Anchor, the name of the Trackable in the World Storage must correspond to the name of Google UUID of the anchor. + +### Geo Trackables ### + +#### iOS: perspectives #### + +On iOS, Geo Trackables are not yet supported with this package. + +A first possibility for adding this support is to adapt the Google GeoSpatial code and then run your iOS application with the ARCore AR backend. + +A second possibility is to add the support for ARKit GeoTracking: https://developer.apple.com/documentation/arkit/arkit_in_ios/content_anchors/tracking_geographic_locations_in_ar +This feature is not implemented yet due to the small number of places supported (see https://developer.apple.com/documentation/arkit/argeotrackingconfiguration) + +#### Android: Google GeoSpatial #### +To come \ No newline at end of file -- GitLab From 086784eb0ea4f4e687493bb1879c34913194f5ca Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Tue, 16 Jul 2024 15:38:16 +0200 Subject: [PATCH 14/21] Implementation of the Geospatial module using ARCore API. Fix a bug in the trackable selection algorithm. Change the way ARAnchorManager is used in the ARCoreAnchors module --- Runtime/ARCoreExtensionsConfig.asset | 2 +- .../Resources/ARFAnchorTrackingPrefab.prefab | 106 ++++++++++ Runtime/Scripts/WorldAnalysisARFoundation.cs | 34 +++- ...dAnalysisARFoundationModuleARCoreAnchor.cs | 10 +- ...rldAnalysisARFoundationModuleGeospatial.cs | 185 ++++++++++++++++++ 5 files changed, 327 insertions(+), 10 deletions(-) create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs diff --git a/Runtime/ARCoreExtensionsConfig.asset b/Runtime/ARCoreExtensionsConfig.asset index 858be38..6b08173 100644 --- a/Runtime/ARCoreExtensionsConfig.asset +++ b/Runtime/ARCoreExtensionsConfig.asset @@ -14,5 +14,5 @@ MonoBehaviour: m_EditorClassIdentifier: CloudAnchorMode: 1 SemanticMode: 0 - GeospatialMode: 0 + GeospatialMode: 2 StreetscapeGeometryMode: 0 diff --git a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab index 4b74c4b..1c0ee73 100644 --- a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab +++ b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab @@ -1,5 +1,110 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &919512057412407595 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5663275178603938767} + - component: {fileID: 2250489381470411502} + - component: {fileID: 5243785181569724411} + - component: {fileID: 4959683567476516339} + m_Layer: 0 + m_Name: PurpleSphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5663275178603938767 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919512057412407595} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 20, y: 20, z: 20} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 6911754431728604849} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2250489381470411502 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919512057412407595} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5243785181569724411 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919512057412407595} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a64202207c2bc6042a40ad749c6eabf1, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!135 &4959683567476516339 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919512057412407595} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} --- !u!1 &6911754431728604848 GameObject: m_ObjectHideFlags: 0 @@ -33,6 +138,7 @@ Transform: - {fileID: 6911754433267149346} - {fileID: 6911754433204531549} - {fileID: 5348077246929615354} + - {fileID: 5663275178603938767} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6911754432812775762 diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 02484a7..28aa10d 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -8,10 +8,11 @@ using System.Collections; using System.Linq; using ETSI.ARF.OpenAPI.WorldStorage; using ETSI.ARF.WorldStorage.REST; +using Unity.XR.CoreUtils; //Implementation of the WorldAnalysis interface public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface -{ +{ /// /// Dictionnary of susbscription informations for poses, for each item, stored using the UUID of the item (anchor/trackable) /// @@ -50,6 +51,11 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface /// private bool isChekingAvailabilityRunning = false; + /// + /// Anchor manager + /// + private ARAnchorManager m_anchorManager; + /// /// Informations regarding a subscription to a pose /// @@ -73,10 +79,13 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface m_relocalizationInformations = new Dictionary(); m_computedPoses = new Dictionary(); m_subscriptionsPoses = new Dictionary(); - + m_trackableModules = new List(); WorldAnalysisARFoundationModuleImage imageModule = new WorldAnalysisARFoundationModuleImage(); m_trackableModules.Add(imageModule); + + WorldAnalysisARFoundationModuleGeospatial geospatialModule = new WorldAnalysisARFoundationModuleGeospatial(); + m_trackableModules.Add(geospatialModule); #if UNITY_IOS WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); m_trackableModules.Add(meshModule); @@ -158,7 +167,9 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface List notTrackedCandidates = new List(); //Hierarchy of types - string[] types = { "MESH", "IMAGE_MARKER", "FIDUCIAL_MARKER", "MAP", "OTHER" }; //TODO : GEOPOSE + string[] types = { "MESH", "IMAGE_MARKER", "FIDUCIAL_MARKER", "MAP", "GEOPOSE", "OTHER" }; + + List keysToRemove = new List(); //We fill in the confidence level lists. foreach (KeyValuePair relocObject in temp) @@ -178,9 +189,18 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface { notTrackedCandidates.Add(relocObject.Value); } + }else + { + keysToRemove.Add(relocObject.Key); } } + // Remove null trackables from temp + foreach (Guid key in keysToRemove) + { + temp.Remove(key); + } + //uses the types[] array indexes as key, and UUIDs as values List> typesSortedList = new List>(); foreach (var relocObject in temp) @@ -365,7 +385,10 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface List capabilities = new List(); foreach (ETSI.ARF.OpenAPI.WorldAnalysis.Capability capability in currentCapabilities) { - capabilities.Add(WorldAnalysisUnityHelper.ConvertWorldAnalysisCapability(capability)); + if(capability != null) + { + capabilities.Add(WorldAnalysisUnityHelper.ConvertWorldAnalysisCapability(capability)); + } } /// Collect relocalization information @@ -544,7 +567,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface /// private Guid SelectTrackableWithTypeAndDistance(List candidates, List> typesSortedList, UnityEngine.Vector3 cameraTransformPos) { - float bestDistance = 100.0f; //valeur par d�faut = grande distance (� changer) + float bestDistance = 10000000.0f; //default value : long distance (to change ?) Guid selectedTrackableUUID = Guid.Empty; //if only one trackable is candidate @@ -602,7 +625,6 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface } } } - return selectedTrackableUUID; } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs index 9bd2d3e..1d5fb50 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -30,9 +30,13 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda public void Initialize() { XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); - m_anchorManager = origin.gameObject.AddComponent(); - GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); - m_anchorManager.anchorPrefab = anchorPrefab; + m_anchorManager = origin.gameObject.GetComponent(); + if (m_anchorManager == null ) + { + m_anchorManager = origin.gameObject.AddComponent(); + GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); + m_anchorManager.anchorPrefab = anchorPrefab; + } m_anchorManager.anchorsChanged += OnTrackedCloudAnchorChanged; } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs new file mode 100644 index 0000000..d57391e --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs @@ -0,0 +1,185 @@ +#if UNITY_ANDROID && ETSIARF_ARCORE_EXTENSIONS +using System; +using System.Collections.Generic; +using Google.XR.ARCoreExtensions; +using Unity.XR.CoreUtils; +using UnityEngine; +using UnityEngine.XR.ARFoundation; +using UnityEngine.XR.ARSubsystems; +using static WorldAnalysisARFoundationModule; + +public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundationModule +{ + /// + /// Anchor manager + /// + private ARAnchorManager m_anchorManager; + + private AREarthManager m_arEarthManager; + + private Dictionary m_trackedGeospatialAnchors = new Dictionary(); + + private bool geospatialSupported = true; + + /// Correspondance between local trackable and etsi uuid + /// + private Dictionary m_localIdToEtsiId = new Dictionary(); + + /// + /// Initialize ARCore geospatial anchors tracking module + /// + public void Initialize() + { + XROrigin origin = UnityEngine.Object.FindAnyObjectByType(); + m_anchorManager = origin.gameObject.GetComponent(); + if (m_anchorManager == null) + { + m_anchorManager = origin.gameObject.AddComponent(); + GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab"); + m_anchorManager.anchorPrefab = anchorPrefab; + } + m_arEarthManager = origin.gameObject.AddComponent(); + m_anchorManager.anchorsChanged += OnTrackedGeospatialAnchorChanged; + } + + /// + /// + /// + /// + /// + public TrackableInfo GetPoseTrackable(Guid uuid) + { + if (m_trackedGeospatialAnchors.ContainsKey(uuid.ToString())) + { + return m_trackedGeospatialAnchors[uuid.ToString()]; + } + else + { + return null; + } + } + + /// + /// + /// + /// + /// + public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) + { + if (!geospatialSupported) return false; + + if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.GEOPOSE) + { + return false; + } + CreateGeosptialAnchor(trackable); + + return true; + } + + + public async void CreateGeosptialAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) + { + if (geospatialSupported) + { + while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None || ARSession.state == ARSessionState.SessionInitializing || m_arEarthManager.EarthState != EarthState.Enabled || m_arEarthManager.EarthTrackingState != TrackingState.Tracking) + { + await System.Threading.Tasks.Task.Delay(100); + } + if (m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled) != FeatureSupported.Supported) + { + Debug.Log("Support : " + m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled)); + geospatialSupported = false; + } + else + { + double[] values = new double[trackable.TrackablePayload.Length / sizeof(double)]; + + for (int i = 0; i < values.Length; i++) + { + values[i] = BitConverter.ToDouble(trackable.TrackablePayload, i * sizeof(double)); + } + + Quaternion rotation = Quaternion.Euler((float)values[3], (float)values[4], (float)values[5]); + + if (m_arEarthManager.EarthTrackingState == TrackingState.Tracking) + { + var anchor = m_anchorManager.AddAnchor(values[0], values[1], values[2], rotation); + m_localIdToEtsiId.Add(anchor.trackableId.subId2.ToString("X16"), trackable.UUID.ToString()); + } + } + } + } + + + /// + /// + /// + /// + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() //s'occuper de ça (fonction doc) + { + if (!geospatialSupported) return null; + + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityGeospatialAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityGeospatialAnchor.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARCORE; + encodingInformation.Version = "1.01"; + capabilityGeospatialAnchor.EncodingInformation = encodingInformation; + capabilityGeospatialAnchor.Framerate = 30; // Not particularly specified on ARKit and ARCore + capabilityGeospatialAnchor.Latency = 0; // Not particularly specified on ARKit and ARCore + capabilityGeospatialAnchor.Accuracy = 1; // Not particularly specified on ARKit and ARCore + return capabilityGeospatialAnchor; + } + + /// + /// + /// + /// + private void OnTrackedGeospatialAnchorChanged(ARAnchorsChangedEventArgs eventArgs) + { + foreach (var trackedGeospatialAnchor in eventArgs.updated) + { + Vector3 position = trackedGeospatialAnchor.transform.position; + Quaternion rotation = trackedGeospatialAnchor.transform.rotation; + + TrackableInfo info = new TrackableInfo(); + info.name = trackedGeospatialAnchor.name; + string localId = trackedGeospatialAnchor.trackableId.subId1.ToString("X16");// there must be a better way : does it work every time? + + if (m_localIdToEtsiId.ContainsKey(localId)) + { + info.name = m_localIdToEtsiId[localId]; + } + else + { + Debug.Log("ARCore Geospatial Anchor No correspondance for Local Anchor " + localId); + continue; + } + + if (trackedGeospatialAnchor.trackingState == TrackingState.Tracking) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 100; + } + else if (trackedGeospatialAnchor.trackingState == TrackingState.Limited) + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; + info.confidence = 50; + } + else + { + info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.FAILURE; //ADD NOT_TRACKED ? + info.confidence = 0; + } + info.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + info.position = position; + info.rotation = rotation; + info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE; + + m_trackedGeospatialAnchors[info.name] = info; + } + } +} + +#endif \ No newline at end of file -- GitLab From 08b37b470112b5b3fb0a1d402b5298011e6805e4 Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Wed, 17 Jul 2024 14:28:11 +0200 Subject: [PATCH 15/21] Add documentation comments for Geospatial and ARCore Cloud Anchors modules --- .../WorldAnalysisARFoundationModule.cs | 7 +- ...dAnalysisARFoundationModuleARCoreAnchor.cs | 12 +-- ...rldAnalysisARFoundationModuleGeospatial.cs | 74 +++++++++++-------- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModule.cs b/Runtime/Scripts/WorldAnalysisARFoundationModule.cs index 4b9d745..7074046 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModule.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModule.cs @@ -30,13 +30,14 @@ public interface WorldAnalysisARFoundationModule public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable); /// - /// + /// Get the pose of the trackable from its uuid /// - /// + /// id of the trackable + /// null or trackableInfo with last updated values public TrackableInfo GetPoseTrackable(Guid uuid); /// - /// Initialize capability object with the features of the + /// Initialize capability object with the features of the module /// public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability(); diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs index 69af489..ff1c4c6 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -74,9 +74,9 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Initialize capability object with the features of the arcore cloud anchor module /// - /// + /// a Capability object public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() { ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityARCoreAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); @@ -92,7 +92,7 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Update arcore cloud anchors informations /// /// private void OnTrackedCloudAnchorChanged(ARAnchorsChangedEventArgs eventArgs) @@ -140,10 +140,10 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Create a new ARCore Cloud anchor using ARCore API id /// /// - private async void AddNewARCoreCloudAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable ) + private async void AddNewARCoreCloudAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None ||ARSession.state == ARSessionState.SessionInitializing) { @@ -172,7 +172,7 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda } /// - /// + /// Resolves cloud anchor promise /// /// /// diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs index d57391e..bd8e034 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs @@ -15,16 +15,26 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati /// private ARAnchorManager m_anchorManager; + /// + /// Earth manager + /// private AREarthManager m_arEarthManager; + /// + /// List of geospatial anchors with tracking infos + /// private Dictionary m_trackedGeospatialAnchors = new Dictionary(); - private bool geospatialSupported = true; - + /// /// Correspondance between local trackable and etsi uuid /// private Dictionary m_localIdToEtsiId = new Dictionary(); + /// + /// Check if ARCore Geospatial is supported on the device + /// + private bool geospatialSupported = true; + /// /// Initialize ARCore geospatial anchors tracking module /// @@ -43,10 +53,10 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } /// - /// + /// Get the pose of the trackable from its uuid /// - /// - /// + /// id of the trackable + /// null or trackableInfo with last updated values public TrackableInfo GetPoseTrackable(Guid uuid) { if (m_trackedGeospatialAnchors.ContainsKey(uuid.ToString())) @@ -60,10 +70,10 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } /// - /// + /// Need to be a geopose /// /// - /// + /// geopose or not (does not check is solved) public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { if (!geospatialSupported) return false; @@ -77,7 +87,30 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati return true; } + /// + /// Initialize capability object with the features of the geospatial module + /// + /// null if ARCore Geospatial is not supported on the device, or a Capability object + public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() + { + if (!geospatialSupported) return null; + ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityGeospatialAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); + capabilityGeospatialAnchor.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE; + ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); + encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARCORE; + encodingInformation.Version = "1.01"; + capabilityGeospatialAnchor.EncodingInformation = encodingInformation; + capabilityGeospatialAnchor.Framerate = 30; // Not particularly specified on ARKit and ARCore + capabilityGeospatialAnchor.Latency = 0; // Not particularly specified on ARKit and ARCore + capabilityGeospatialAnchor.Accuracy = 1; // Not particularly specified on ARKit and ARCore + return capabilityGeospatialAnchor; + } + + /// + /// Creates a new ARCore Geospatial anchor using informations from a geopose trackable object + /// + /// public async void CreateGeosptialAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { if (geospatialSupported) @@ -88,7 +121,6 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } if (m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled) != FeatureSupported.Supported) { - Debug.Log("Support : " + m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled)); geospatialSupported = false; } else @@ -111,31 +143,10 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } } - - /// - /// - /// - /// - public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability() //s'occuper de ça (fonction doc) - { - if (!geospatialSupported) return null; - - ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityGeospatialAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability(); - capabilityGeospatialAnchor.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE; - ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure(); - encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARCORE; - encodingInformation.Version = "1.01"; - capabilityGeospatialAnchor.EncodingInformation = encodingInformation; - capabilityGeospatialAnchor.Framerate = 30; // Not particularly specified on ARKit and ARCore - capabilityGeospatialAnchor.Latency = 0; // Not particularly specified on ARKit and ARCore - capabilityGeospatialAnchor.Accuracy = 1; // Not particularly specified on ARKit and ARCore - return capabilityGeospatialAnchor; - } - /// - /// + /// Update geospatial anchors informations /// - /// + /// Event arguments for the event private void OnTrackedGeospatialAnchorChanged(ARAnchorsChangedEventArgs eventArgs) { foreach (var trackedGeospatialAnchor in eventArgs.updated) @@ -181,5 +192,4 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } } } - #endif \ No newline at end of file -- GitLab From c090e25c3e145337104e736a52ea24c329903a51 Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Mon, 29 Jul 2024 15:05:56 +0200 Subject: [PATCH 16/21] Add debug lines and modify tracking prefab aspect for geospatial trackables --- Runtime/Resources/ARFAnchorTrackingPrefab.prefab | 2 +- Runtime/Scripts/WorldAnalysisARFoundation.cs | 6 +++++- .../WorldAnalysisARFoundationModuleGeospatial.cs | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab index 1c0ee73..e50e5ac 100644 --- a/Runtime/Resources/ARFAnchorTrackingPrefab.prefab +++ b/Runtime/Resources/ARFAnchorTrackingPrefab.prefab @@ -18,7 +18,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!4 &5663275178603938767 Transform: m_ObjectHideFlags: 0 diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index b40662f..34925a2 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -393,8 +393,13 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface } } + /// Collect relocalization information ETSI.ARF.OpenAPI.WorldStorage.Response response = RelocalizationInformationRequest.GetRelocalizationInformation(m_worldStorageServer, uuids, modes, capabilities); + if(response == null) + { + Debug.Log("ESTI ARF GetRelocalizationInformation : request response is null"); + } relocInfo = response.RelocInfo.First(); //Only one uuid requested } else @@ -408,7 +413,6 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface /// Subscription not possible return InformationSubscriptionResult.NONE; } - return CreateSubscriptionWithRelocalizationInformation(relocInfo, uuid, mode, callback, ref validity, out subscriptionUUID); } diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs index bd8e034..6a8c093 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs @@ -76,6 +76,7 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati /// geopose or not (does not check is solved) public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { + Debug.Log("GEO : Add Geosptial Trackable"); if (!geospatialSupported) return false; if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.GEOPOSE) @@ -113,19 +114,29 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati /// public async void CreateGeosptialAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { + + double[] values = new double[trackable.TrackablePayload.Length / sizeof(double)]; + + for (int i = 0; i < values.Length; i++) + { + values[i] = BitConverter.ToDouble(trackable.TrackablePayload, i * sizeof(double)); + } + if (geospatialSupported) { while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None || ARSession.state == ARSessionState.SessionInitializing || m_arEarthManager.EarthState != EarthState.Enabled || m_arEarthManager.EarthTrackingState != TrackingState.Tracking) { + Debug.Log("Geo : checking " + ARSession.state + " " + m_arEarthManager.EarthState + " " + m_arEarthManager.EarthTrackingState); await System.Threading.Tasks.Task.Delay(100); } if (m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled) != FeatureSupported.Supported) { geospatialSupported = false; + Debug.Log("Geo : not supported"); } else { - double[] values = new double[trackable.TrackablePayload.Length / sizeof(double)]; + values = new double[trackable.TrackablePayload.Length / sizeof(double)]; for (int i = 0; i < values.Length; i++) { @@ -164,7 +175,7 @@ public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundati } else { - Debug.Log("ARCore Geospatial Anchor No correspondance for Local Anchor " + localId); + //Debug.Log("ARCore Geospatial Anchor No correspondance for Local Anchor " + localId); continue; } -- GitLab From c3d24c72e09793bce95d4f7d769d79a108f3b5c7 Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Tue, 30 Jul 2024 11:40:30 +0200 Subject: [PATCH 17/21] Add missing meta file --- .../WorldAnalysisARFoundationModuleGeospatial.cs.meta | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs.meta diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs.meta b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs.meta new file mode 100644 index 0000000..205e77f --- /dev/null +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleGeospatial.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2230c312c9cd04c488d9d8a3e058f39b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab From 46a28b9db6ba195e81bf5f9c3599d20a36202717 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Tue, 30 Jul 2024 21:39:55 +0200 Subject: [PATCH 18/21] fix build on iOS (caused by geospatial), arkit map now only track if anchor is tracked (update readme accordingly) --- README.md | 2 +- Runtime/Scripts/WorldAnalysisARFoundation.cs | 4 ++-- .../Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 24c4251..237c53b 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ https://developer.apple.com/documentation/arkit/arworldmap The .map file can be placed in the Unity persistent data path of the application on the user device with the following name: "ARkitWorlMap.map". Alternatively, the variable keyvalueTags of the Trackable can also contain a parameter with the "url" key providing a link to download the map file. -By default, the origin of the Map Trackable is the point (0, 0 ,0). If the Map includes an Anchor, you can use it as the origin by setting the name of the Trackable in the World Storage with the TrackableId of the ARAnchor stored in the map. https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/api/UnityEngine.XR.ARSubsystems.TrackableId.html +The map needs to include at least one Anchor. You can use one of them as the origin of the map by setting the name of the Trackable in the World Storage with the TrackableId of the ARAnchor stored in the map. https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@5.1/api/UnityEngine.XR.ARSubsystems.TrackableId.html Samples for creating and serializing an ARWorldMap with ARFoundation can be found here: https://github.com/Unity-Technologies/arfoundation-samples/blob/main/Assets/Scripts/Runtime/ARWorldMapController.cs diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 34925a2..97f94a9 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -84,8 +84,6 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface WorldAnalysisARFoundationModuleImage imageModule = new WorldAnalysisARFoundationModuleImage(); m_trackableModules.Add(imageModule); - WorldAnalysisARFoundationModuleGeospatial geospatialModule = new WorldAnalysisARFoundationModuleGeospatial(); - m_trackableModules.Add(geospatialModule); #if UNITY_IOS WorldAnalysisARFoundationModuleMesh meshModule = new WorldAnalysisARFoundationModuleMesh(); m_trackableModules.Add(meshModule); @@ -98,6 +96,8 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface // todo add script define symbol for using arcore extensions WorldAnalysisARFoundationModuleARCoreAnchor arCoreAnchorModule = new WorldAnalysisARFoundationModuleARCoreAnchor(); m_trackableModules.Add(arCoreAnchorModule); + WorldAnalysisARFoundationModuleGeospatial geospatialModule = new WorldAnalysisARFoundationModuleGeospatial(); + m_trackableModules.Add(geospatialModule); #else /// on other os : if arcore extensions is in the scene we disable it Google.XR.ARCoreExtensions.ARCoreExtensions arCoreExtensions = Component.FindObjectOfType(); diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs index 5b1ef20..7019f3a 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARKitWorldMap.cs @@ -231,7 +231,7 @@ public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFound data.Dispose(); } sessionSubsystem.ApplyWorldMap(worldMap); - UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map + //UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map } } } -- GitLab From 02e1a1e9f05de709bde69921a9258485a7afac44 Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Thu, 1 Aug 2024 10:52:45 +0200 Subject: [PATCH 19/21] Remove some debug lines and update some comments --- .../WorldAnalysisARFoundationModuleARCoreAnchor.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs index ff1c4c6..15a1ac3 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundationModuleARCoreAnchor.cs @@ -64,7 +64,7 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda /// map or not (does not check is solved) public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable) { - /// Here : we don't check if the trackable is allready added, AddImageToLibrary does it + /// Here : we don't check if the trackable is allready added if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.MAP) { return false; @@ -102,7 +102,6 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda Vector3 position = trackedCloudAnchor.transform.position; Quaternion rotation = trackedCloudAnchor.transform.rotation; - TrackableInfo info = new TrackableInfo(); info.name = trackedCloudAnchor.name; string localId = trackedCloudAnchor.trackableId.subId1.ToString("X16");// there must be a better way : does it work every time? @@ -182,13 +181,8 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda var result = promise.Result; if (result.CloudAnchorState == CloudAnchorState.Success) { - Debug.Log("ARCloud Anchor Resolve Sucess" +cloudId); m_localIdToEtsiId.Add(result.Anchor.trackableId.subId2.ToString("X16"), etsiId); // should be a better way: not sure about that but subId2 of the ARCloudAnchor seems to correspond to subId1 of local anchor that is updated by Anchor Manager } - else - { - Debug.Log("ARCloud Anchor Resolve Failed" + result.CloudAnchorState + " " +cloudId); - } } } -- GitLab From e3f665589d6968807dda665da6c206f6eb7f17b9 Mon Sep 17 00:00:00 2001 From: Sylvain Buche Date: Thu, 1 Aug 2024 15:33:14 +0200 Subject: [PATCH 20/21] Update README.md --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 237c53b..ddda2ae 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ https://github.com/Unity-Technologies/arfoundation-samples/blob/main/Assets/Scri #### Android ARCore Cloud Anchors #### -On Android/ARcore Map Trackables are supported with Cloud Anchors. +On Android/ARCore Map Trackables are supported with Google Cloud Anchors. Cloud Anchors are anchors that are hosted on the ARCore API cloud endpoint. This hosting enables users to share experiences in the same app: see https://developers.google.com/ar/develop/cloud-anchors @@ -91,4 +91,15 @@ A second possibility is to add the support for ARKit GeoTracking: https://develo This feature is not implemented yet due to the small number of places supported (see https://developer.apple.com/documentation/arkit/argeotrackingconfiguration) #### Android: Google GeoSpatial #### -To come \ No newline at end of file + +On Android/ARCore Geo Trackables are supported with Google Geospatial Anchors. + +Geospatial Anchors are anchors that are hosted on the ARCore API cloud endpoint. This hosting enables users to share experiences in the same app using GPS and Google Earth data: see https://developers.google.com/ar/develop/geospatial + +For using ARCore Geospatial Anchors you need to: +* Add the the arcore unity extensions package as a dependency of the Unity project https://github.com/google-ar/arcore-unity-extensions +* Add to the runtime asmdef of this package a reference to Google.XR.ARCoreExtensions.asmdef +* Add a new Script Define Symbol in the Unity project settings: "ETSIARF_ARCORE_EXTENSIONS" +* Then, follow the instructions detailed here https://developers.google.com/ar/develop/unity-arf/geospatial/enable-android and here https://developers.google.com/ar/develop/authorization?platform=unity-arf to configure the project and your google cloud account + +To use a Geo Pose Trackable that corresponds to a Google Geospatial Anchor, the payload of the Trackable in the World Storage must be an array of doubles following this format : [latitude, longitude, altitude, rotationX, rotationY, rotationZ] in base 64. -- GitLab From ebbecbf8b801a311b4fa070a18812fa3395b8eba Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Wed, 25 Sep 2024 18:35:23 +0200 Subject: [PATCH 21/21] Type changed for matrix4x4 conversion --- Runtime/Scripts/WorldAnalysisARFoundation.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Runtime/Scripts/WorldAnalysisARFoundation.cs b/Runtime/Scripts/WorldAnalysisARFoundation.cs index 97f94a9..0292ec0 100644 --- a/Runtime/Scripts/WorldAnalysisARFoundation.cs +++ b/Runtime/Scripts/WorldAnalysisARFoundation.cs @@ -235,7 +235,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface continue; } - Matrix4x4 tr = WorldAnalysisUnityHelper.ConvertETSIARFTransform3DToUnity(firstRelocInfo.Transform3D); + Matrix4x4 tr = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(firstRelocInfo.Transform3D); // Changed to WS / SylR UnityEngine.Vector3 tr_trans = WorldAnalysisUnityHelper.ExtractTranslationFromMatrix(tr); UnityEngine.Quaternion tr_rot = WorldAnalysisUnityHelper.ExtractRotationFromMatrix(tr); @@ -395,10 +395,10 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface /// Collect relocalization information - ETSI.ARF.OpenAPI.WorldStorage.Response response = RelocalizationInformationRequest.GetRelocalizationInformation(m_worldStorageServer, uuids, modes, capabilities); + ETSI.ARF.OpenAPI.WorldStorage.RelocalizationInformations response = RelocalizationInformationRequest.GetRelocalizationInformation(m_worldStorageServer, uuids, modes, capabilities); if(response == null) { - Debug.Log("ESTI ARF GetRelocalizationInformation : request response is null"); + Debug.Log("ETSI ARF GetRelocalizationInformation : request response is null"); } relocInfo = response.RelocInfo.First(); //Only one uuid requested } @@ -449,7 +449,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface l_modes.Add(Mode_WorldStorage.TRACKABLES_TO_REQUEST); } /// Collect relocalization information - ETSI.ARF.OpenAPI.WorldStorage.Response response = RelocalizationInformationRequest.GetRelocalizationInformation(m_worldStorageServer, l_uuids, l_modes, capabilities); + ETSI.ARF.OpenAPI.WorldStorage.RelocalizationInformations response = RelocalizationInformationRequest.GetRelocalizationInformation(m_worldStorageServer, l_uuids, l_modes, capabilities); /// Check every reloc information object foreach (RelocalizationInformation relocInfo in response.RelocInfo) @@ -506,7 +506,7 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface } } - public InformationSubscriptionResult UnSubscribeToPose(Guid subscriptionUUID) + public InformationSubscriptionResult UnsubscribeFromPose(Guid subscriptionUUID) { if (m_subscriptionsPoses.ContainsKey(subscriptionUUID)) { -- GitLab