Skip to content
Snippets Groups Projects
Commit 086784eb authored by Sylvain Buche's avatar Sylvain Buche
Browse files

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
parent 5ca2a94b
No related branches found
No related tags found
1 merge request!2WA now supports multiple trackable modules, add module mesh for iOS,...
......@@ -14,5 +14,5 @@ MonoBehaviour:
m_EditorClassIdentifier:
CloudAnchorMode: 1
SemanticMode: 0
GeospatialMode: 0
GeospatialMode: 2
StreetscapeGeometryMode: 0
%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
......
......@@ -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
{
{
/// <summary>
/// Dictionnary of susbscription informations for poses, for each item, stored using the UUID of the item (anchor/trackable)
/// </summary>
......@@ -50,6 +51,11 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface
/// </summary>
private bool isChekingAvailabilityRunning = false;
/// <summary>
/// Anchor manager
/// </summary>
private ARAnchorManager m_anchorManager;
/// <summary>
/// Informations regarding a subscription to a pose
/// </summary>
......@@ -73,10 +79,13 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface
m_relocalizationInformations = new Dictionary<Guid, ETSI.ARF.OpenAPI.WorldStorage.RelocalizationInformation>();
m_computedPoses = new Dictionary<Guid, ETSI.ARF.OpenAPI.WorldAnalysis.Pose>();
m_subscriptionsPoses = new Dictionary<Guid, SubscriptionInfo>();
m_trackableModules = new List<WorldAnalysisARFoundationModule>();
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<RelocObjects> notTrackedCandidates = new List<RelocObjects>();
//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<Guid> keysToRemove = new List<Guid>();
//We fill in the confidence level lists.
foreach (KeyValuePair<Guid, RelocObjects> 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<KeyValuePair<string, Guid>> typesSortedList = new List<KeyValuePair<string, Guid>>();
foreach (var relocObject in temp)
......@@ -365,7 +385,10 @@ public class WorldAnalysisARFoundation : MonoBehaviour, WorldAnalysisInterface
List<ETSI.ARF.OpenAPI.WorldStorage.Capability> capabilities = new List<ETSI.ARF.OpenAPI.WorldStorage.Capability>();
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
/// <returns></returns>
private Guid SelectTrackableWithTypeAndDistance(List<RelocObjects> candidates, List<KeyValuePair<string, Guid>> 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;
}
......
......@@ -30,9 +30,13 @@ public class WorldAnalysisARFoundationModuleARCoreAnchor : WorldAnalysisARFounda
public void Initialize()
{
XROrigin origin = UnityEngine.Object.FindAnyObjectByType<XROrigin>();
m_anchorManager = origin.gameObject.AddComponent<ARAnchorManager>();
GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab");
m_anchorManager.anchorPrefab = anchorPrefab;
m_anchorManager = origin.gameObject.GetComponent<ARAnchorManager>();
if (m_anchorManager == null )
{
m_anchorManager = origin.gameObject.AddComponent<ARAnchorManager>();
GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab");
m_anchorManager.anchorPrefab = anchorPrefab;
}
m_anchorManager.anchorsChanged += OnTrackedCloudAnchorChanged;
}
......
#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
{
/// <summary>
/// Anchor manager
/// </summary>
private ARAnchorManager m_anchorManager;
private AREarthManager m_arEarthManager;
private Dictionary<string, TrackableInfo> m_trackedGeospatialAnchors = new Dictionary<string, TrackableInfo>();
private bool geospatialSupported = true;
/// Correspondance between local trackable and etsi uuid
/// </summary>
private Dictionary<string, string> m_localIdToEtsiId = new Dictionary<string, string>();
/// <summary>
/// Initialize ARCore geospatial anchors tracking module
/// </summary>
public void Initialize()
{
XROrigin origin = UnityEngine.Object.FindAnyObjectByType<XROrigin>();
m_anchorManager = origin.gameObject.GetComponent<ARAnchorManager>();
if (m_anchorManager == null)
{
m_anchorManager = origin.gameObject.AddComponent<ARAnchorManager>();
GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab");
m_anchorManager.anchorPrefab = anchorPrefab;
}
m_arEarthManager = origin.gameObject.AddComponent<AREarthManager>();
m_anchorManager.anchorsChanged += OnTrackedGeospatialAnchorChanged;
}
/// <summary>
///
/// </summary>
/// <param name="uuid"></param>
/// <returns></returns>
public TrackableInfo GetPoseTrackable(Guid uuid)
{
if (m_trackedGeospatialAnchors.ContainsKey(uuid.ToString()))
{
return m_trackedGeospatialAnchors[uuid.ToString()];
}
else
{
return null;
}
}
/// <summary>
///
/// </summary>
/// <param name="trackable"></param>
/// <returns></returns>
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());
}
}
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
///
/// </summary>
/// <param name="eventArgs"></param>
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment