VR网络图片加载造成的丢帧问题

  最近在跟一个VR项目。需要将从服务器返回的数据展示在VR商品列表里面。使用的是UGUI,每当图片异步加载返回刷新UI界面时会出现卡帧的现象,根据图片大小不同相应的卡1-3帧。造成很不好的用户体验。

  根据网上参考,使用了AsyncImageDownload(http://blog.csdn.net/daijinghui512/article/details/38066119)来做图片异步加载的封装。但在VR中出现了卡帧的问题。代码如下:

using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
public class AsyncImageDownload : MonoBehaviour
{

public Texture placeholder;
public static AsyncImageDownload Instance = null;

private string path = Application.persistentDataPath + "/ImageCache/";


void Awake()
{
   
}
//构建单例  
public static AsyncImageDownload CreateSingleton()
{
    if (!Directory.Exists(Application.persistentDataPath + "/ImageCache/"))
    {
        Directory.CreateDirectory(Application.persistentDataPath + "/ImageCache/");
    }

    GameObject obj = new GameObject();
    obj.name = "AsyncImageDownload";
    obj.AddComponent();

    AsyncImageDownload loader = obj.GetComponent();
    Instance = loader;  
    loader.placeholder = Resources.Load("placeholder") as Texture;
    return loader;

}

public void SetAsyncImage(string url, RawImage texture)
{



    //开始下载图片前,将UITexture的主图片设置为占位图  
    texture.texture = placeholder;

    //判断是否是第一次加载这张图片  

    if (!File.Exists(path + url.GetHashCode()))
    {
        //如果之前不存在缓存文件  


        StartCoroutine(DownloadImage(url, texture));


    }
    else
    {

        StartCoroutine(LoadLocalImage(url, texture));

    }

}
IEnumerator DownloadImage(string url, RawImage texture)
{
    Debug.Log("downloading new image:" + path + url.GetHashCode());
    WWW www = new WWW(url);
    yield return www;

    Texture2D image = www.texture;
    //将图片保存至缓存路径  
    byte[] pngData = image.EncodeToPNG();
    File.WriteAllBytes(path + url.GetHashCode(), pngData);

    texture.texture = image;

}
IEnumerator LoadLocalImage(string url, RawImage texture)
{
    string filePath = "file:///" + path + url.GetHashCode();

    Debug.Log("getting local image:" + filePath);
    WWW www = new WWW(filePath);
    yield return www;


    //直接贴图  
    texture.texture = www.texture;

  }  
}

  根据自己项目本身的需求对这个异步加载图片做了很多修改和处理。经过Unity Profiler的跟踪定位到了问题。

  • CoroutineDelayCall中AsyncImageDownload 协程的MoveNext占用了cpu大多时间50ms-500ms不等。从而造成了卡帧。

  • 原因定位:

    • byte[] pngData = image.EncodeToPNG(); 将纹理转换为字节流时发生了耗时操作。
    • File.WriteAllBytes(path + url.GetHashCode(), pngData);将纹理存储本地化时IO发生了耗时。
  • Coroutine协程并不等于线程。只是通过IEnumerator接口中的MoveNext实现了控制代码在特定的时间段执行。耗时操作仍然影响主线程的UI刷新造成卡帧现象。

  • VR中占用cpu最多的是Camera.Render,通过Normalized View Port Rect实现双眼相机分屏渲染,对于渲染开销很大(尤其是在移动端),当IO流或者其他加载耗时操作时,由于Camra每帧都在渲染画面,会出现卡帧。

  • 解决方案,通过线程池来进行网络请求图片的加载以及本地化缓存。

  构建图片的数据模型ImageModel:

using UnityEngine;
using System.Collections;
using System.IO;


public class ImageModel  {

string path;

public string Path
{
    get { return path; }
    set { path = value; }
}

Texture2D imageData;

public Texture2D ImageData
{
    get { return imageData; }
    set { imageData = value; }
}
public ImageModel() { }
public ImageModel(string path, Texture2D tex) { this.Path = path; this.ImageData = tex; }

public void DownImageLocalization(object obj)
{
    ImageModel temp = obj as ImageModel;
    byte[] pngData = temp.ImageData.EncodeToPNG();
    File.WriteAllBytes(temp.Path, pngData);
}

}

  修改加载方案:

 Texture2D image = www.texture;

    //压缩
    image.Compress(false);
    //替换
    texture.texture = image;
    
    //将图片保存至缓存路径
    ImageModel im = new ImageModel(path + url.GetHashCode(), image);
    ThreadPool.QueueUserWorkItem(new WaitCallback(im.DownImageLocalization),im);
  • 解决VR卡帧问题,主要针对移动端VR。

  欢迎讨论各种缺陷与不足,本人原创转载请注明文章出处,谢谢。

你可能感兴趣的:(VR网络图片加载造成的丢帧问题)