Skip to content
Snippets Groups Projects
WorldAnalysisARFoundationModuleMesh.cs 7.74 KiB
Newer Older
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
{
    /// <summary>
    /// ARFoundation Image tracking management
    /// </summary>
    private ARTrackedObjectManager m_trackedObjectManager;
    /// <summary>
    /// Name of all meshes that have been added to the library
    /// </summary>
    private List<string> m_trackedMeshesInLibrary; 
    /// <summary>
    /// List of tracked meshses with tracking infos
    /// </summary>
    private Dictionary<string,TrackableInfo> m_trackedMeshes = new Dictionary<string,TrackableInfo>();
     /// <summary>
    /// Link between trackable name and uuid
    /// </summary>
    private Dictionary<Guid, string> m_uuidToName  = new Dictionary<Guid, string >();
     /// <summary>
    /// Bundle with all the  XRReferenceObjectEntry
    /// </summary>
    private XRReferenceObjectEntry []  m_entries  ;

    /// <summary>
    /// Initialize image tracking module
    /// </summary>
    public void Initialize()
    {
        XROrigin origin = UnityEngine.Object.FindAnyObjectByType<XROrigin>();
        m_trackedObjectManager = origin.gameObject.AddComponent<ARTrackedObjectManager>();
        XRReferenceObjectLibrary library = (XRReferenceObjectLibrary) ScriptableObject.CreateInstance(typeof(XRReferenceObjectLibrary));
        m_trackedObjectManager.referenceLibrary = library ;
        m_trackedMeshesInLibrary = new List<string>();
        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<XRReferenceObjectEntry>() ;
        }
    }

    /// <summary>
    ///  found  
    /// </summary>
    /// <param name="uuid">name of the mesh trackable</param>
    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; 
    }

    /// <summary>
    /// Add a trackable : need to be an image
    /// </summary>
    /// <param name="trackable">Image trackable</param>
    /// <returns>Supported or not</returns>
    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;
    }

    /// <summary>
    ///  Initialize capability object with image tracking
    /// </summary>
    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 ;
    }

    /// <summary>
    /// Event manager for when a mesh is tracked
    /// </summary>
    /// <param name="eventArgs">the event</param>
    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;
        }
    }

    /// <summary>
    /// Add a new mesh to the arfoundation library
    /// </summary>
    /// <param name="fileName">file name</param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// Add a Mesh 
    /// </summary>
    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
    }
}