Unity实用小工具或脚本

您所在的位置:网站首页 unity加载大量外部图片 Unity实用小工具或脚本

Unity实用小工具或脚本

2023-05-07 03:53| 来源: 网络整理| 查看: 265

Unity实用小工具或脚本—加载外部图片的三种方式 发表于2017-12-20 评论0 2.4k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学堂游戏程序行业精英群

711501594 一、前言       项目上需要加载多个地图,每个地图的贴图将近200M,所有地图加起来贴图将近2G。因此,想着能不能将贴图放到工程外加载,逐研究了一下,得出了三种加载方式,分别是WWW加载、C#原生的IO加载在转换成Texture2D和Assetbundle打包和加载,下面就给大家介绍下这三种加载外部图片的方式。       前面两种方式都会存在卡顿现象,因为最消耗性能的计算方式最终都还是放在主线程里。尽管第二种方式可以使用另外一个线程加载图片成Bytes数组,但是将字节数组转成成Texture2D还是在主线程里,而这个过程在图片5M的时候还是很卡顿,何况我的地形贴图每张有20M左右。对于前面两种方式没有找到任何其他好的优化方式来解决。第三种方式是我用到最理想的,在加载的过程中不会有卡顿。二、WWW加载首先,获取当前工程同目录下的“MapImages”文件夹路径,然后获取每张图片的全部路径,并将路径存到列表中。 /// /// 获取当前物体应该读取的地形贴图的文件的路径 /// /// private string GetFilePath() { string[] strTempPath = Application.dataPath.Split('/'); string strPath = string.Empty; //去掉后面两个,获取跟工程相同目录的路径,如“E:/ZXB/MyProject/Asset/",去掉后面两个就得到和工程同级的目录为:“E:/ZXB” for (int i = 0; i < strTempPath.Length-2; i++) { strPath += strTempPath[i] + "/"; } //加上整个地形贴图的文件命 strPath += TERRAINMAP_FILENAME + "/"; //最后加上当前文件夹的名称,最后的文件夹名称和当前物体的名称一致 strPath += gameObject.name + "/"; return strPath; } /// /// 获取所有地图贴图文件路径 /// /// private void GetAllFile(FileSystemInfo info) { if (!info.Exists) { Debug.Log("该路径不存在!"); return; } DirectoryInfo dir = info as DirectoryInfo; if(null==dir) { Debug.Log("该目录不存在!"); return; } FileSystemInfo[] si = dir.GetFileSystemInfos(); for (int i = 0; i < si.Length; i++) { FileInfo fi = si[i] as FileInfo; if(null!=fi&&IsImage(fi.Extension)) { listStrFileName.Add(fi.FullName); } else { } } } 然后根据路径列表使用WWW逐个加载图片 /// /// 根据文件路径加载图片 /// private IEnumerator GetAllTexture() { curFilePath = GetFilePath(); DirectoryInfo tempInfo = new DirectoryInfo(curFilePath); GetAllFile(tempInfo); foreach (string item in listStrFileName) { WWW www = new WWW("file://" + item); yield return www; //先得到最后的图片文件名 string[] tempAllFileName = item.Split(Path.DirectorySeparatorChar); //去掉后缀 string tempStrKey = tempAllFileName[tempAllFileName.Length - 1]; tempStrKey = tempStrKey.Substring(0, tempStrKey.Length - 4).Trim(); if(null!=tempStrKey&&!dicTextures.ContainsKey(tempStrKey)) { dicTextures.Add(tempStrKey, www.texture); } else { Debug.LogError("图片文件名为空或者有相同的文件名!"); continue; } if(dicSubTerrainMat.ContainsKey(tempStrKey)) { dicSubTerrainMat[tempStrKey].SetTexture("_MainTex", www.texture); } else { Debug.LogError("文件名"+tempStrKey+"在材质列表中没有找到对应的材质名!"); } } isLoadAllTexture = true; Debug.Log("Load All Terrain Texture!"); } 效果图如图所示:一开始显示的是默认模糊处理的贴图,在加载的过程中帧率非常低,造成卡顿。二、IO文件流加载       首先,同样的是加载文件路径。然后开启另外一个线程将图片的字节流加载到字典中。 /// /// 根据文件路径读取图片并转换成byte /// /// /// public static byte[] ReadPictureByPath(string path) { FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); fileStream.Seek(0, SeekOrigin.Begin); byte[] binary = new byte[fileStream.Length]; fileStream.Read(binary, 0, (int)fileStream.Length); fileStream.Close(); fileStream.Dispose(); fileStream = null; return binary; } 然后,加载整个文件列表里的图片到字典缓存中。 /// /// 根据文件路径加载图片 /// private void GetAllTerrainTex() { DirectoryInfo tempInfo = new DirectoryInfo(curFilePath); GetAllFile(tempInfo); foreach (string item in listStrFileName) { byte[] tempImageBuffer = ReadPictureByPath(item); if(null==tempImageBuffer) { Debug.Log("读取路径"+item+"图片失败!"); } string[] tempAllFileName = item.Split(Path.DirectorySeparatorChar); //去掉后缀 string tempStrKey = tempAllFileName[tempAllFileName.Length - 1]; tempStrKey = tempStrKey.Substring(0, tempStrKey.Length - 4).Trim(); if (null != tempStrKey && !dicImageBuffer.ContainsKey(tempStrKey)) { dicImageBuffer.Add(tempStrKey, tempImageBuffer); } else { Debug.LogError("图片文件名为空或者有相同的文件名!"); continue; } } isLoadAllTexture = true; Debug.Log("Load All Terrain Texture!");} 最终的加载效果图如图所示:同样会导致帧率很低造成卡顿,但是这种方式有一个好处是可以先将图片使用其他线程加载到缓存中,造成卡顿是因为将字节流转成Texture2D  Texture2D tempTex = new Texture2D(TERRAIN_MAP_DI, TERRAIN_MAP_DI); tempTex.LoadImage(item.Value); 这里的地形贴图都很大,就算单张图片压缩到4M左右,使用LoadImage方法还是会卡顿。而这个方法又只能在主线程里使用,也即不能在新开的加载线程里使用。Unity对这类的类都限制了,只能在主线程使用。三、Assetbundle打包再加载       首先,要将贴图导入到Unity工程里面,然后对一个文件夹里的贴图进行打包。.0之后的打包方式比较简单,如图所示: 先选中要打包的贴图,在Inspectors面板下有个AssetBundle,这里新建你要打包成集合的名字,我以文件夹的名字新建了一个标签“40_73.4_36.69237_77.61875”。选中文件夹里其他图片,将它们都设置成这个标签。这样就可以将整个文件夹里的图片打包成一个集合,方便一次性加载。       打包的代码和简单,可以在Editor文件下,创建一个编辑脚本,代码如下: [MenuItem("Example/Build Asset Bundles")] static void BuildABs() { // Put the bundles in a folder called "ABs" within the Assets folder. BuildPipeline.BuildAssetBundles("Assets/Assetbundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows); } 对比以前的方式,新的打包方法确实简化方便了很多。接下来将打包好的Assetbundle文件夹放到工程的同级目录下,加载Assetbuudle的代码如下: /// ///异步加载地形的贴图 /// /// private IEnumerator SetAllTexAsy() { yield return null; var bundleLoadRequest = AssetBundle.LoadFromFileAsync(curFilePath); yield return bundleLoadRequest; var myLoadedAssetBundle = bundleLoadRequest.assetBundle; if (myLoadedAssetBundle == null) { Debug.Log("Failed to load AssetBundle!"); yield break; } foreach (var item in dicSubTerrainMat) { var assetLoadRequest = myLoadedAssetBundle.LoadAssetAsync(item.Key); yield return assetLoadRequest; Texture2D tempTex = assetLoadRequest.asset as Texture2D; if (null == tempTex) { Debug.Log(gameObject.name + "Assetbundle里没有对应" + item.Key + "的贴图"); } else { item.Value.SetTexture("_MainTex", tempTex); } } myLoadedAssetBundle.Unload(false); } 加载得到集合包,然后根据每个图片的文件名得到具体的图片。最终的效果图如图所示:可以看到帧率几乎不受任何影响,但是会在加载到显示的过程中停留2秒时间左右,对于程序的卡顿,这个时间的停滞还是可以接受的。四、总结虽然,第三种方式在加载的时候比较流畅,不会影响到主线程的执行。但是,打包的过程也是一个很繁琐,且需要细致认真的工作。总的来说第三种方式最好的,前面两种方式应该用在其他方面,几天的研究算是作为一个记录,或许以后就能用的上。

原文链接

著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签:

UnityAssetBundleJavaScript

本文作者

feng 暂无简介 Mesh绘制交互网格 Unity基本介绍与使用 Unity使用RenderTexture实现实时阴影绘制 Unity 贴图压缩方法及对比 Unity3D AsssetBundle加载效率比较 GWB公众号 腾讯游戏学堂公众号


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3