From c273ed9f691f0e8d79290b83de4cebe30a243a93 Mon Sep 17 00:00:00 2001
From: jlacoche <jeremy.lacoche@orange.com>
Date: Wed, 26 Jun 2024 17:20:57 +0200
Subject: [PATCH] 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
     /// <summary>
     /// Name of all meshes that have been added to the library
     /// </summary>
-    private List<string> m_trackedMeshesInLibrary; 
+    private List<string> m_trackedMeshesInLibrary;
+    /// <summary>
+    /// Has downloaded asset bundle from an url
+    /// </summary>
+    private bool m_hasDownloadedBundle; 
     /// <summary>
     /// List of tracked meshses with tracking infos
     /// </summary>
@@ -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<XRReferenceObjectEntry>() ;
-        }
+        m_hasDownloadedBundle = false; 
     }
 
     /// <summary>
@@ -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
     }
 
     /// <summary>
-    ///  Initialize capability object with image tracking
+    ///  Initialize capability object with Mesh tracking
     /// </summary>
     public ETSI.ARF.OpenAPI.WorldAnalysis.Capability  GetSupportedCapability()
     {
@@ -153,7 +160,7 @@ public class WorldAnalysisARFoundationModuleMesh : WorldAnalysisARFoundationModu
     /// </summary>
     /// <param name="fileName">file name</param>
     /// <returns></returns>
-    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<string, string> 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<XRReferenceObjectEntry>();
+            }
+            else
+            {
+                return false;
+            }
         }
     
         XRReferenceObjectEntry toAdd = null ;
-- 
GitLab