在Unity3D中加載外部圖片的兩種方法

喜聞樂見的WWW方式

  喜聞樂見的WWW方式之所以喜聞樂見,這是因爲這是我們最爲熟悉的一種,我們都知道通過WWW可以從網絡上加載文本、圖片、音頻等形式的內容,那麼通過WWW能否加載本地外部(相對於應用程序)資源呢?答案是肯定的,這是因爲WWW可以支持http和file兩種協議。我們通常接觸到的WWW默認都是指http協議,現在我們來說說file協議,該協議可以用來訪問本地資源(絕對路徑)。例如我們希望加載文件D:\TestFile\pic001.png這個文件,則此時對應的C#腳本爲:

1
2
3
4
5
6
7
8
9
//請求WWW
WWW www = new WWW("file://D:\\TestFile\\pic001.png);
yield return www;
if(www != null && string.IsNullOrEmpty(www.error))
{
//獲取Texture
Texture texture=www.texture;
//更多操作...
}

注意到這裏出現了yield return結構,這表示這裏使用到了協程,因此我們需要付出的代價就是需要在項目中使用StartCoroutine等協程相關的方法來調用這些協程。雖然在Unity3D中使用協程是件簡單的事情,可是如果我們隨隨便便地使用協程而不注意去維護這些協程,那麼這些讓我們引以爲傲的簡單代碼可能就會變成我們痛苦不堪的無盡深淵。

亙古不變的傳統IO方式

  好了,下面我們隆重推出亙古不變的傳統IO方式,這種方式相信大家都沒有接觸過,所以這裏將這種方法和大家分享。既然是傳統的IO方式,那麼無非就是各種IO流的處理啦。好,我們一起來看下面這段代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//創建文件讀取流
FileStream fileStream = new FileStream(screen, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
//創建文件長度緩衝區
byte[] bytes = new byte[fileStream.Length];
//讀取文件
fileStream.Read(bytes, 0, (int)fileStream.Length);
//釋放文件讀取流
fileStream.Close();
fileStream.Dispose();
fileStream = null;

//創建Texture
int width=800;
int height=640;
Texture2D texture = new Texture2D(width, height);
texture.LoadImage(bytes);

可以看到在使用這種方式讀取圖片文件的時候主要是將圖片文件轉化爲byte[]數組,再利用Texture2D的LoadImage方法轉化爲Unity3D中的Texture2D。這種方法需要在創建過程中傳入圖片的大小,在這裏我們創建了一張800X640的圖片。經過博主的研究發現,這種方式加載外部圖片相對於使用WWW加載外部圖片效率更高,所以如果大家遇到類似的需求,博主個人推薦大家使用這種方式進行加載。

  到目前爲止我們解決了如何從外部加載圖片到Unity3D中,現在我們回到最開始的問題,我們從外部讀取到這些圖片以後需要將它們加載到遊戲界面中。比如當我們使用UGUI的時候,UGUI中的Image控件需要一個Sprite來作爲它的填充內容,那麼此時我們就需要將Texture轉化爲Sprite.號了,下面我們給出一個簡單的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.IO;

public class TestLoading : MonoBehaviour
{
/// <summary>
/// Image控件
/// </summary>
private Image image;

void Start ()
{
image = this.transform.Find("Image").GetComponent<Image>();

//爲不同的按鈕綁定不同的事件
this.transform.Find("LoadByWWW").GetComponent<Button>().onClick.AddListener
(
delegate(){LoadByWWW();}
);

this.transform.Find("LoadByIO").GetComponent<Button>().onClick.AddListener
(
delegate(){LoadByIO();}
);
}

/// <summary>
/// 以IO方式進行加載
/// </summary>
private void LoadByIO()
{
double startTime = (double)Time.time;
//創建文件讀取流
FileStream fileStream = new FileStream("D:\\test.jpg", FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
//創建文件長度緩衝區
byte[] bytes = new byte[fileStream.Length];
//讀取文件
fileStream.Read(bytes, 0, (int)fileStream.Length);
//釋放文件讀取流
fileStream.Close();
fileStream.Dispose();
fileStream = null;

//創建Texture
int width = 300;
int height = 372;
Texture2D texture = new Texture2D(width, height);
texture.LoadImage(bytes);

//創建Sprite
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
image.sprite = sprite;

startTime=(double)Time.time-startTime;
Debug.Log("IO加載用時:" + startTime);
}

/// <summary>
/// 以WWW方式進行加載
/// </summary>
private void LoadByWWW()
{
StartCoroutine(Load());
}

IEnumerator Load()
{
double startTime = (double)Time.time;
//請求WWW
WWW www = new WWW("file://D:\\test.jpg");
yield return www;
if(www != null && string.IsNullOrEmpty(www.error))
{
//獲取Texture
Texture2D texture=www.texture;

//創建Sprite
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
image.sprite = sprite;

startTime = (double)Time.time - startTime;
Debug.Log("WWW加載用時:" + startTime);
}
}
}

  現在我們運行程序可以發現兩種方式均可以讓圖片加載進來,爲了對比兩種方式在執行效率上的高低,我們在腳本中加入了相關代碼,通過對比可以發現使用IO方式加載一張227k的圖片需要的時間爲0s,而使用WWW方式加載需要0.0185s,因此傳統的IO方式具有更高的效率,建議大家在遇到這類問題時儘可能地使用這種方式。好了,今天的內容就是這樣啦,歡迎大家在我的博客中留言、歡迎大家關注和支持我的博客,謝謝大家!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章