赞
踩
前期需要准备的资源:
1..gbl后缀的模型文件,其中包含了纹理、贴图等模型所依赖的文件,放在unity可以直接使用,不用在后续使用代码添加材质。谨记:模型文件、贴图文件不要出现中文,json反序列化时会报错的。
2.添加**GLTFUtility-master插件下载**
3.从Unity Window->PackageManage中输入com.unity.nuget.newtonsoft-json包名称添加 Newtonsoft.Json-for-Unity
.glb文件处理
限制了同时只能加载一个模型,进行等待和分优先级处理,直接看代码
using Siccity.GLTFUtility; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; /// <summary> /// 加载优先级 /// </summary> public enum WaitLoadFilePriority { HIGH=0, LOW, MIDDLE, NUM, } //每一个需要加载的模型保存数据 public class AsyncLoadResParam { public string filepath=""; //有可能有多处需要加载模型,为避免重复加载,此处只进行回调函数的增加 public List<Action<GameObject>> Callbacks = new List<Action<GameObject>>(); } /// <summary> /// 加载GLB模型单例 /// </summary> public class GLTFUtilityScript { //存储所有未进行加载的,等待的文件 protected List<AsyncLoadResParam>[] m_WaitLoadFiles=new List<AsyncLoadResParam>[(int)WaitLoadFilePriority.NUM]; //当前正在加载的模型 protected AsyncLoadResParam cuResParam; //是否加载中 bool isLoading = false; //使用一个不会被隐藏的对象,需要自己在其他地方赋值 public MonoBehaviour mono; private static GLTFUtilityScript instance; public static GLTFUtilityScript Instance { get { if (instance == null) { instance = new GLTFUtilityScript(); } return instance; } } public void Init() { for (int i = 0; i < (int)WaitLoadFilePriority.NUM; i++) { m_WaitLoadFiles[i]=new List<AsyncLoadResParam>(); } } /// <summary> /// 异步加载 gltf and glb /// </summary> /// <param name="filepath">路径</param> protected void ImportGLTFAsync(string filepath) { isLoading = true; mono.CancelInvoke(CheckLoadState);//每次加载时需要先结束上次检查事件 mono.StartCoroutine(LoadModel(filepath, OnLoadComplete)); } /// <summary> /// 加载模型 /// </summary> /// <param name="path"></param> /// <param name="callback"></param> /// <returns></returns> private IEnumerator LoadModel(string path,Action<GameObject> callback=null) { var request = UnityWebRequest.Get(path); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { callback(null); Debug.LogError(request.error); } else { mono.Invoke(CheckLoadState,10f); //开启10s检测时间,防止处于卡死状态 var obj= Importer.LoadFromBytes(request.downloadHandler.data); while (obj==null) yield return null; callback(obj); } } //10s检测时间,如果文件错误的等无法加载的情况,终止当前加载,防止处于卡死状态 private void CheckLoadState() { if (isLoading) { isLoading = false; for (int i = 0; i < cuResParam.Callbacks.Count; i++) { Debug.Log("10s检测时间,防止处于卡死状态"); cuResParam.Callbacks[i]?.Invoke(null); } DeleteAsyncLoadResParam(); CheckAsyncLoadResParam(); } } /// <summary> /// 加载完后的回调 /// </summary> /// <param name="result">加载出来的物体</param> /// <param name="clip"></param> void OnLoadComplete(GameObject obj) { isLoading = false; for (int i = 0; i < cuResParam.Callbacks.Count; i++) { cuResParam.Callbacks[i]?.Invoke(obj); } DeleteAsyncLoadResParam(); CheckAsyncLoadResParam(); } /// <summary> /// 检查字典里需要加载的资源,是否继续下载模型 /// </summary> /// <returns></returns> protected void CheckAsyncLoadResParam() { Debug.Log("检查是否继续执行"); for (int i = 0; i < m_WaitLoadFiles.Length; i++) { if (m_WaitLoadFiles[i].Count>0) { cuResParam=m_WaitLoadFiles[i][0]; ImportGLTFAsync(m_WaitLoadFiles[i][0].filepath); return; } } } /// <summary> /// 添加模型加载 /// </summary> /// <param name="path"></param> /// <param name="callback"></param> public void AddAsyncLoadResParam(string path, Action<GameObject> callback=null,WaitLoadFilePriority priority=WaitLoadFilePriority.MIDDLE) { Debug.Log("添加模型加载"); for (int i = 0; i < m_WaitLoadFiles[(int)priority].Count; i++) { if (m_WaitLoadFiles[(int)priority][i].filepath.Equals(path)) { if (callback!=null) { m_WaitLoadFiles[(int)priority][i].Callbacks.Add(callback); return; } } } var item = new AsyncLoadResParam(); item.filepath = path; item.Callbacks.Add(callback); m_WaitLoadFiles[(int)priority].Add(item); if (!isLoading) { CheckAsyncLoadResParam(); } } /// <summary> /// 删除需要加载的资源 /// </summary> /// <returns></returns> protected void DeleteAsyncLoadResParam() { for (int i = 0; i < m_WaitLoadFiles.Length; i++) { if (m_WaitLoadFiles[i].Count>0) { for (int j = 0; j < m_WaitLoadFiles[i].Count; j++) { if (cuResParam==m_WaitLoadFiles[i][j]) { m_WaitLoadFiles[i].Remove(m_WaitLoadFiles[i][j]); return; } } } } } }
调用示例
private static Dictionary<string,GameObject> m_AlreadyLoadedDic=new Dictionary<string, GameObject>(); //记得初始化 public static void Init(MonoBehaviour temp) { mono = temp; GLTFUtilityScript.Instance.Init(); } //供外界用来加载模型的调用 public static void LoadModel(string filePath, Action<GameObject> callback) { //文件名 string fileName=filePath.Remove(0, filePath.LastIndexOf("/") + 1); GameObject temp = null; if (!m_AlreadyLoadedDic.TryGetValue(fileName,out temp) && temp==null) { GLTFUtilityScript.Instance.AddAsyncLoadResParam(filePath, (go) => { if (!m_AlreadyLoadedDic.ContainsKey(fileName)) { Debug.Log("成功保存模型到本地"); //添加到本地字典保存 m_AlreadyLoadedDic.Add(fileName,go); callback.Invoke(go); } }); } else { callback.Invoke(temp); } } //调用示例 LoadModel(tidePlayInfo.workImgUrl, (go) => { if (go!=null) { var temp= Instantiate(go, transform); temp.gameObject.SetActive(true); Debug.Log("模型加载成功"); } else { Debug.Log("模型加载未成功"); } }
踩坑笔记
1.使用 unity2021版本的同学,请使用GLTFUtility-master.7.2之前的版本,不要想着去卸载unity的依赖包newtonsoft-json,他没有问题!
2.WebGl开发的同学特别注意 补充!!!巨坑!!!
(1). 当你使用 JsonConvert.DeserializeObject方法打印出正确的信息后,就要知道序列化和反序列化是没有问题的
(2).当你排查很久发现C#的Task类不执行,任务状态一直处于WaitingToRun,不要考虑是因为WebGl不支持多线程的原因
解决方案 :加载glb模型请用 Importer.LoadFromBytes,不要使用Importer.LoadFromFileAsync,不要问,问就是血的教训。下面是执行代码,替换上面的加载glb模型调用方法。
/// <summary> /// 加载模型 /// </summary> /// <param name="path">路径</param> /// <param name="callback">回调方法</param> /// <returns></returns> private IEnumerator LoadModel(string path,Action<GameObject> callback=null) { var request = UnityWebRequest.Get(path); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { Debug.LogError(request.error); } else { callback(Importer.LoadFromBytes(request.downloadHandler.data)); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。