【问题标题】:How to access files in the Hololens 3D object Folder如何访问 Hololens 3D 对象文件夹中的文件
【发布时间】:2020-08-30 04:42:58
【问题描述】:

我正在开发一个使用 Trilib 加载 3D 模型的应用程序。目前该应用程序在 Unity 中运行,PC 3D 模型文件夹中的任何 fbx 文件都可以通过远程全息加载到 HoloLens 中。当我构建应用程序并部署到 HL 时,我看不到任何文件。我已经设置了 3D Objects 文件夹的权限..

using System;
using System.Collections;
using System.Linq;
using System.IO;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.Experimental.UI;
using TMPro;
using TriLib;

#if ENABLE_WINMD_SUPPORT
using System.Threading.Tasks;
using Windows.Storage;
#endif

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace HololensProject {

    public class HModelLoader : SingletonBehaviour<HModelLoader> {

        [Header("UI")]
        [SerializeField] private Transform m_content;
        [SerializeField] private ScrollingObjectCollection m_scrollingCollection;
        [SerializeField] private GameObject m_textButtonPrefab;
        [SerializeField] private TextMeshPro m_currentPathTMP;

        [Header("Model Load")]
        [SerializeField] private Transform m_modelLoadArea;
        [SerializeField] private RuntimeAnimatorController m_runtimeAnimatorController;
        [SerializeField] private GameObject m_modelComponentPrefab;

        [SerializeField, HideInInspector] private byte[] m_defaultModelData;
        private static string[] m_directoryFiles;

        void Start() {
            m_content.gameObject.GetChilds().Destroy();
            m_scrollingCollection.UpdateCollection();

            StartCoroutine(ListModels());
        }

        IEnumerator LoadModels() {
            var loaded = false;

#if ENABLE_WINMD_SUPPORT
            var modelData = m_defaultModelData;

            Task.Run(async () => {
                if (await KnownFolders.Objects3D.TryGetItemAsync("molecule_default.fbx") == null) {
                    var defaultModel = await KnownFolders.Objects3D.CreateFileAsync("molecule_default.fbx");
                    await FileIO.WriteBytesAsync(defaultModel, modelData);
                }

                var allModels = await KnownFolders.Objects3D.GetFilesAsync();

                Dispatcher.Instance.Invoke(() => {
                    m_currentPathTMP.text = KnownFolders.Objects3D.Path.Replace(@"\", "/");
                    m_directoryFiles = allModels.Where(f => f.FileType.ToLower() == ".fbx").Select(f => f.Path).ToArray();
                });
            });
#else
            var userPath = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).Parent.Parent.FullName;
            var objects3DPath = Path.Combine(userPath, "3D Objects");

            Directory.CreateDirectory(objects3DPath);

            if (!File.Exists(objects3DPath + "/molecule_default.fbx"))
                File.WriteAllBytes(objects3DPath + "/molecule_default.fbx", m_defaultModelData);

            m_currentPathTMP.text = objects3DPath.Replace(@"\", "/");
            m_directoryFiles = new DirectoryInfo(objects3DPath).GetFiles().Where(f => f.Extension.ToLower() == ".fbx").Select(f => f.FullName).ToArray();
            loaded = true;
#endif
            while (!loaded) 
                yield return null;
        }

        IEnumerator ListModels() {
            yield return LoadModels();

            if (m_directoryFiles.Length == 0)
                yield break;

            for (var i = 0; i < m_directoryFiles.Length; i++) {
                var button = Instantiate(m_textButtonPrefab, m_content).GetComponent<Interactable>();
                var tmp = button.transform.Find("IconAndText/TextMeshPro").GetComponent<TextMeshPro>();
                var filePath = m_directoryFiles[i];

                tmp.text = Path.GetFileName(m_directoryFiles[i]);

                button.OnClick.AddListener(() => {
#if ENABLE_WINMD_SUPPORT
                    Task.Run(async () => {
                        if (await StorageFile.GetFileFromPathAsync(filePath) != null)
                            Dispatcher.Instance.Invoke(() => LoadModel(filePath, Instantiate(Instance.m_modelComponentPrefab)));
                    });
#else
                    if (!File.Exists(filePath))
                        return;

                    LoadModel(filePath, Instantiate(Instance.m_modelComponentPrefab));
#endif
                });
            }

            m_scrollingCollection.UpdateCollection();
        }

        static void LoadModel(string modelPath, GameObject wrapperGameObject) {
            using (var assetLoaderAsync = new AssetLoaderAsync()) {
                var assetLoaderOptions = AssetLoaderOptions.CreateInstance();

                assetLoaderOptions.UseLegacyAnimations = false;
                assetLoaderOptions.AnimatorController = Instance.m_runtimeAnimatorController;

                var thread = assetLoaderAsync.LoadFromFile(modelPath, assetLoaderOptions, null, delegate (GameObject loadedModel) {
                    loadedModel.name = Path.GetFileNameWithoutExtension(modelPath);
                    loadedModel.transform.SetParent(wrapperGameObject.transform);
                    wrapperGameObject.transform.SetParent(Instance.m_modelLoadArea);

                    var c = loadedModel.GetComponentsInChildren<Renderer>();

                    foreach (var x in c)
                        x.gameObject.AddComponent<BoxCollider>();

                    var x1 = wrapperGameObject.GetComponent<Microsoft.MixedReality.Toolkit.Experimental.UI.BoundsControl.BoundsControl>();
                    var x2 = wrapperGameObject.GetComponent<ManipulationHandler>();

                    x1.BoundsOverride = c.FirstOrDefault().GetComponent<BoxCollider>();
                    x1.Awake();
                    x2.Awake();

                    wrapperGameObject.transform.localScale = new Vector3(.1f, .1f, .1f);
                });
            }
        }

#if UNITY_EDITOR
        [Header("Editor")]
        [SerializeField] private GameObject m_defaultTestModel;

        void OnValidate() {
            if (m_defaultTestModel && (null != m_defaultModelData || m_defaultModelData.Length == 0)) {
                var modelPath = AssetDatabase.GetAssetPath(m_defaultTestModel);
                m_defaultModelData = File.ReadAllBytes(modelPath);
            }
        }
#endif
    }
}

【问题讨论】:

  • -1 表示未指定语言

标签: c# hololens


【解决方案1】:

虽然可以通过StorageFileClass获取Object3D库中文件的引用,但不能通过路径直接访问Library文件夹中的文件。

但是你可以使用内存作为后备存储读取文件数据,然后调用TriLib.AssetLoaderAsync.LoadFromMemory()从内存中加载数据。

首先,您需要调用IStorageFile.OpenStreamForReadAsync() 来检索要从 StorageFile 实例读取的流。然后调用该实例的CopyTo()方法将字节复制到另一个MemoryStream实例,最后使用其ToArray()方法将其转换为byte[],

经过这些步骤,你会得到一个byte[]类数据,可以作为参数调用TriLib.AssetLoaderAsync.LoadFromMemory()

【讨论】:

  • 你能帮我看看代码吗?我不是开发人员.. 谢谢 Hernando..
  • @CarlosArrieta 我建议您与团队一起完成修改,如果您遇到特定的编码问题,我们愿意为您提供帮助。
猜你喜欢
  • 2022-01-02
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
  • 2014-02-26
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多