后台线程读取本地或云端 png\jpg 图像。html
背景:VR开发中最常用的功能之一是加载外部全景图并显示在头盔中。但是一张4K全景图的大小往往在10M左右,需要占用24M(4K jpg格式,1像素24bit-RGB)内存。如果在主线程中加载,会明显感觉卡顿,而在VR模式下,用户对卡顿的感知会被放大。幸运的是,新版本的 Unity 为我们提供了在一个工作线程中完成这个文件加载和图像解析的过程。网络
使用WWW类或者IO方式确实可以让文件加载在后台线程中完成,但是加载的数据解析到Texture类中时,在之前的版本中只能在主线程中完成unity 读取图片硬件设备,unity会分配它一次满足这个图像的内存,并读取所有的像素。此行为使此操作非常耗时。虽然对于小图片,这仍然没有问题。异步
Texture2D tex; tex = new Texture2D(4, 4, TextureFormat.DXT1, false); using (WWW www = new WWW(url)) { yield return www; www.LoadImageIntoTexture(tex); GetComponent<Renderer>().material.mainTexture = tex; // 或者是下面这样 // GetComponent().material.mainTexture =www.texture; }
上面的方法非常简单可靠,加载一些小图没有问题,几乎兼容所有版本的unity。假设使用这种方法,有一些问题需要注意 svg
加载图片的长度和宽度要尽量接近2的n次方,否则会比预期浪费更多的内存空间,加载速度也会变慢。如果加载的镜像不再需要,需要手动销毁,即使没有引用unity也不会被GC自动回收。如果不需要透明通道unity 读取图片,尽量使用jpg格式的图片代替png,这样可以节省1/4的内存(RGB24->RGBA32)
说完了传统的加载方式,我们来介绍一下Unity新支持的异步图片加载功能。这隐藏在文档深处,可能很多人都没有发现。优化
IEnumerator GetTexture() { //这里的地址能够填本地文件地址 file://[文件路径] using(UnityWebRequest www = UnityWebRequest.GetTexture("http://www.my-server.com/image.png")) { yield return www.Send(); if(www.isError) { Debug.Log(www.error); } else { /*这里把贴图转换的过程放到了后台线程来完成, 而且相比于直接脚本加载图片作了优化,减小了内存分配*/ Texture myTexture = DownloadHandlerTexture.GetContent(www); } } }
Unity2018.2.12中的UnityWebRequest类被UnityWebRequestTexture替代了,但是用法完全一样。
unity2018文档地址url