美文网首页unity
VR网络图片加载造成的丢帧问题

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

作者: Levi_Wan | 来源:发表于2017-08-16 21:36 被阅读96次

      最近在跟一个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>();
    
        AsyncImageDownload loader = obj.GetComponent<AsyncImageDownload>();
        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网络图片加载造成的丢帧问题

        本文链接:https://www.haomeiwen.com/subject/ewjwrxtx.html