using GLTFast; using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using UnityEngine; public class SceneManagementGLTF : MonoBehaviour { /// <summary> /// Path to GLTF File (relative to streaming assets in editor, else persistentdatapath) /// </summary> public string _PathToGLTF; /// <summary> /// Validity in milliseconds for a subscription to the WA /// </summary> public int _ValiditySubscription = 100000; /// <summary> /// List of trackables and anchors in the AR Scene /// </summary> private Dictionary<Guid, Transform> m_trackablesAndAnchorsInARScene; /// <summary> /// Unity Start Method /// </summary> protected async void Start() { m_trackablesAndAnchorsInARScene = new Dictionary<Guid, Transform>(); await LoadGltfBinaryFromMemory(); Transform loaded = this.transform.GetChild(0); FindWorldStorageTransform(loaded); foreach(KeyValuePair<Guid , Transform> toSubscribe in m_trackablesAndAnchorsInARScene) { int validity = _ValiditySubscription; Guid subscriptionUUID; // TODO : if only one : subscribeToPose, if multiple subscribetoPoses WorldAnalysisInterface.Instance.SubscribeToPose(null, toSubscribe.Key, ETSI.ARF.OpenAPI.WorldAnalysis.Mode_WorldAnalysis.DEVICE_TO_TRACKABLES, PoseCallback, ref validity, out subscriptionUUID); //TODO : find a value for the token parameter. } } /// <summary> /// The callback function used in the susbscription method. It instantiate a prefab or update its pose based on the current situation. /// </summary> /// <param name="result"></param> /// <param name="pose"> The pose to update in the SM</param> public void PoseCallback(WorldAnalysisInterface.PoseEstimationResult result, ETSI.ARF.OpenAPI.WorldAnalysis.Pose pose) { if (pose.EstimationState != ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK) { Debug.Log("State Not Ok for " + pose.Uuid + " "+ pose.EstimationState.ToString() + " " + pose.InstructionInfo); return; } if (pose.Value.Type == ETSI.ARF.OpenAPI.WorldAnalysis.PoseValueType.VECTOR_QUATERNION) { ETSI.ARF.OpenAPI.WorldAnalysis.VectorQuaternionPoseValue value = (ETSI.ARF.OpenAPI.WorldAnalysis.VectorQuaternionPoseValue)pose.Value; if (m_trackablesAndAnchorsInARScene.ContainsKey(pose.Uuid)) { m_trackablesAndAnchorsInARScene[pose.Uuid].transform.position = WorldAnalysisUnityHelper.ConvertETSIVector3ToUnity(value.Position); m_trackablesAndAnchorsInARScene[pose.Uuid].transform.rotation = WorldAnalysisUnityHelper.ConvertETSIARFQuaternionToUnity(value.Rotation); } else { Debug.LogWarning("Callback for unwanted uuid"); } } else { Debug.LogWarning("Pose value type not supported yet :" +pose.Value.Type); // Todo : manage other types } } /// <summary> /// Load a GLTF from local memory according to _PathToGLTF /// </summary> /// <returns>ascync method</returns> protected async Task LoadGltfBinaryFromMemory() { #if UNITY_EDITOR string prefix = Application.streamingAssetsPath; #else string prefix = Application.persistentDataPath; #endif var filePath = prefix + "/" + _PathToGLTF; Debug.Log("PATH : " + filePath); byte[] data = File.ReadAllBytes(filePath); Debug.Log("File Size " + data.Length); var gltf = new GltfImport(); bool success = await gltf.LoadGltfBinary( data, // The URI of the original data is important for resolving relative URIs within the glTF new Uri(filePath) ); GameObjectInstantiator instantiator = new GameObjectInstantiator(gltf, this.transform); if (success) { success = await gltf.InstantiateMainSceneAsync(instantiator); } } /// <summary> /// In the loaded GLTF File : find all World Storage Trackables and Anchors /// </summary> /// <param name="transform">Loaded GLTF Transform</param>s protected void FindWorldStorageTransform(Transform trGLTF) { if (trGLTF.name.StartsWith("ws:")) { string id = trGLTF.name.Substring(3); Debug.Log("Add " + id + " " + trGLTF.name); m_trackablesAndAnchorsInARScene.Add(new Guid(id), trGLTF); } foreach(Transform child in trGLTF) { FindWorldStorageTransform(child); } } }