Thomas Fransolet 0310d28b5e Canal VR Meta Quest : projet Unity, viewer web et documentation
Premier commit du cinquième front. Trois parties :

- `unity/MyInfoMateVR/` : le projet Unity (6000.0.83f1, URP, Meta XR SDK 205),
  un APK unique pour tous les clients. Menu flottant à sélection au regard,
  appairage, chargement de scène GLB, POI, cache de contenu, télémétrie.
- `unity-overlay/` : les mêmes scripts à recopier sur un projet Unity neuf, avec
  les pièges rencontrés consignés dans son README.
- `viewer/` : viewer et éditeur de scène web autonome (Vite, TypeScript,
  three.js), partagé avec les autres fronts.
- `docs/` : état des lieux, setup Unity, décisions d'architecture et plan
  d'exécution en 9 étapes.

La scène est décrite par un `scene.json` poussé par `adb push` : l'app le
préfère à celui embarqué dans l'APK.

Les binaires (GLB, textures de l'échantillon Sponza, DLL Meta XR) passent par
Git LFS dès ce premier commit — les y faire entrer après coup demanderait de
réécrire l'historique. Les artefacts régénérés par l'éditeur et par CMake
(`Library/`, `.utmp/`, Burst debug) sont ignorés.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:26:07 +02:00

54 lines
2.0 KiB
C#

using System;
using System.Threading.Tasks;
using GLTFast;
using UnityEngine;
namespace MyInfoMate.Vr.Scene
{
/// <summary>
/// Chargement d'un GLB <b>au runtime</b>, jamais par glisser-déposer dans l'éditeur.
/// C'est toute la différence : un asset posé dans la scène part dans l'APK et fige
/// le contenu au build. Ici, le fichier peut venir de StreamingAssets aujourd'hui
/// et du cache disque demain, sans changer une ligne d'appelant.
/// </summary>
public static class GltfLoader
{
public static async Task<GameObject> LoadAsync(string url, Transform parent, string name)
{
var import = new GltfImport();
var watch = System.Diagnostics.Stopwatch.StartNew();
if (!await import.Load(url))
{
Debug.LogError($"[GltfLoader] Chargement impossible : {url}");
return null;
}
var root = new GameObject(name);
root.transform.SetParent(parent, false);
if (!await import.InstantiateMainSceneAsync(root.transform))
{
Debug.LogError($"[GltfLoader] Instanciation impossible : {url}");
UnityEngine.Object.Destroy(root);
return null;
}
Debug.Log($"[GltfLoader] {name} chargé en {watch.ElapsedMilliseconds} ms");
return root;
}
/// <summary>
/// Sur Android, StreamingAssets est <b>à l'intérieur de l'APK</b> : le chemin
/// est une URI <c>jar:file://…!/assets/…</c> que seul UnityWebRequest sait lire.
/// Sur desktop c'est un chemin de fichier ordinaire. glTFast gère les deux, à
/// condition qu'on lui passe une URI et pas un chemin concaténé à la main.
/// </summary>
public static string StreamingAssetsUrl(string fileName)
{
var path = System.IO.Path.Combine(Application.streamingAssetsPath, fileName);
return path.Contains("://") ? path : new Uri(path).AbsoluteUri;
}
}
}