Unity 非同步載入圖片
阿新 • • 發佈:2019-02-05
最近做專案處理實時接收資料,每條資料對應一張圖片,為了提高效能,
先顯示每條資料對應生成模型,然後將圖片做好與模型的對映,然後再加上圖片校驗碼和模型之間的校驗碼作比較
等待圖片下載完畢後,會將圖片準確無誤的給對應的模型。
首先思路是
1.客戶端接收 伺服器發來的每條資料,其中資料中包含圖片連結,客戶端先
將模型給建立並顯示,然後在模型上顯示Loading載入(ugui可以做進度條)
2.將img url給放到佇列中 ,每幀都會去檢查當前開啟協程的個數假定最多為30個,
不到30,就開啟協程用www 下載圖片 計數加1,直到協程數量為30,就等待其它協程釋放,然
後繼續從佇列取資料下載。
3.www 下載完畢後,通知檢視層接收圖片,協程釋放計數減1
最後程式碼:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using System.Net;
public struct ImageEvent
{
/// <summary>
/// 圖片和對應的UI對映
/// </summary>
public int key ;
/// <summary>
/// 圖片校驗碼,採用時間作為校驗
/// </summary>
public string verifyCode;
/// <summary>
/// 圖片要下載的地址
/// </summary>
public string url;
/// <summary>
///( x,y)裁剪原點 (z,w)圖片寬高
/// </summary>
public Vector4 imginfo ;
/// <summary>
/// 圖片格式
/// </summary>
public TextureFormat textureFormat;
/// <summary>
/// 圖片寬
/// </summary>
public int width;
/// <summary>
/// 圖片高
/// </summary>
public int height;
}
public class IMGDownManager : MonoBehaviour {
private static IMGDownManager _instance;
public static IMGDownManager Instance
{
get {
return _instance;
}
}
private Queue<ImageEvent> threadEvents = new Queue<ImageEvent>();
private int limitCoroutineCount=30;
private int currentCoroutineCount=0;
private void Awake()
{
_instance = this;
}
/// <summary>
/// 新增事件
/// </summary>
public void AddEvent(ImageEvent imageEvent)
{
threadEvents.Enqueue(imageEvent);
}
public void OnUpdate()
{
if(threadEvents.Count > 0&¤tCoroutineCount<=limitCoroutineCount)
{
ImageEvent threadEvent = threadEvents.Dequeue();
try
{
currentCoroutineCount+=1;
StartCoroutine(OnDownLoad(threadEvent));
}
catch (System.Exception ex)
{
}
}
}
IEnumerator OnDownLoad(ImageEvent imageEvent)
{
using (WWW www=new WWW(imageEvent.url))
{
yield return www;
if (www.error!=null)
{
Debug.LogError("targetId:"+ imageEvent.key+ "圖片地址:"+ imageEvent.url+"下載錯誤資訊:"+ www.error);
//如果下載失敗,再放回佇列裡重新下載
AddEvent(imageEvent);
currentCoroutineCount -= 1;
}
else
{
currentCoroutineCount -= 1;
Texture2D temp;
if (imageEvent.imginfo != Vector4.zero)
{
temp = ScaleTextureCutOut(www.texture, imageEvent.imginfo.z,
imageEvent.imginfo.w, (int)imageEvent.imginfo.x, (int)imageEvent.imginfo.y);
}
else
{
if (imageEvent.width!=0&&imageEvent.height!=0)
{
temp = new Texture2D(imageEvent.width, imageEvent.height, imageEvent.textureFormat, false);
}
temp = www.texture;
}
if (CenterAction.LoadCompleteImg!=null)
{
// Debug.Log("imageEvent key:"+imageEvent.key);
CenterAction.LoadCompleteImg(imageEvent.key,imageEvent.verifyCode,temp);
}
temp = null;
}
}
}
/// <summary>
/// 截圖函式
/// </summary>
/// <param name="TUnit"></param>
Texture2D ScaleTextureCutOut(Texture2D originalTexture, float originalWidth, float originalHeight, int distancex, int distancey)
{
Texture2D newTexture = new Texture2D(Mathf.CeilToInt(originalWidth), Mathf.CeilToInt(originalHeight));
int maxX = originalTexture.width - 1;
int maxY = originalTexture.height - 1;
for (int y = 0; y < newTexture.height; y++)
{
for (int x = 0; x < newTexture.width; x++)
{
float targetX = x;
float targetY = y;
int x1 = Mathf.Min(maxX, Mathf.FloorToInt(targetX));
int y1 = Mathf.Min(maxY, Mathf.FloorToInt(targetY));
int x2 = Mathf.Min(maxX, x1 + 1);
int y2 = Mathf.Min(maxY, y1 + 1);
float u = targetX - x1;
float v = targetY - y1;
float w1 = (1 - u) * (1 - v);
float w2 = u * (1 - v);
float w3 = (1 - u) * v;
float w4 = u * v;
Color color1 = originalTexture.GetPixel(x1 + distancex, y1 + distancey);
Color color2 = originalTexture.GetPixel(x2 + distancex, y1 + distancey);
Color color3 = originalTexture.GetPixel(x1 + distancex, y2 + distancey);
Color color4 = originalTexture.GetPixel(x2 + distancex, y2 + distancey);
Color color = new Color(Mathf.Clamp01(color1.r * w1 + color2.r * w2 + color3.r * w3 + color4.r * w4),
Mathf.Clamp01(color1.g * w1 + color2.g * w2 + color3.g * w3 + color4.g * w4),
Mathf.Clamp01(color1.b * w1 + color2.b * w2 + color3.b * w3 + color4.b * w4),
Mathf.Clamp01(color1.a * w1 + color2.a * w2 + color3.a * w3 + color4.a * w4)
);
newTexture.SetPixel(x, y, color);
}
}
newTexture.anisoLevel = 2;
newTexture.Apply();
Destroy(originalTexture);
return newTexture;
}
private void Update()
{
OnUpdate();
}
}