2013-01-08 163 views
5

我正在通過更改紋理來修改應用於對象的材質,但問題是我在做這件事情時遇到了一些滯後現象。unity3d中預加載紋理

如何預加載內存中的某些紋理以避免unity3d中的時間延遲?

+0

採取的想法,這是非常相似,你的[其它文章](http://stackoverflow.com/questions/13974108/load-materials-on-objects-in-async-方法)。 – Jerdak

+0

@Jerdak沒有它,在那篇文章中,我有興趣加載異步的圖像。在這裏,我有興趣在預加載圖像。 – Alex

回答

4

您是否在加載之前加載紋理?新紋理如何存儲?通常,預先緩存在Awake()或Start()循環期間完成。

Renderer objectRenderer; 
public Texture2D replacementTextureAsset; 
Texture2D runtimeTextureReplacement; 

void Awake() 
{ 
    objectRenderer = (Renderer)GetComponent(typeof(Renderer)); 

    // Either have the texture assigned via the inspector (replacementTextureAsset above) 
    // or else get a reference to it at runtime. Either way, the texture will be loaded into memory by the end of this loop. 
    runtimeTextureReplacement = Resources.Load("myReplacementAsset"); 
} 

void TextureReplace() // Called whenever 
{ 
    objectRenderer.material.texture = replacementTextureAsset; 

    OR 

    objectRenderer.material.texture = runtimeTextureReplacement; 
} 

如果這是你已經在做,你仍然有「滯後」,那麼你很可能遇到發送紋理圖形卡上的幀緩衝區的必然結果。在這種情況下,除了使用較小的紋理之外,沒有什麼可以做的。

0

我給你的問題多一點思考,這裏是我的建議,這是哈克,我希望我沒有這個代碼用我的名字聯繫起來:

public bool TextureCached = false; 
public bool TextureLoaded = false; 
public bool TextureLoadReady = false; 
public string TexturePath = ""; 
public int MaxPixelConvert = 1000; 

Texture2D cached_texture = null; 
public Vector2 last_pixel = new Vector2(0,0); 

// Use this for initialization 
void Start() { 
    SwapMainTexture(); 
    StartWorker(); 
} 

void StartWorker(){ 
    Thread t1 = new Thread (new ThreadStart (this.ListenForUpdate)); 
    t1.Start(); 
} 

/// <summary> 
/// Reads new texture from TexturePath 
/// </summary> 
IEnumerator ReadNewTexture(){ 
    UnityEngine.WWW urltexture = new WWW(TexturePath); 
    yield return urltexture; 

    cached_texture = urltexture.texture; 

    TextureLoadReady = false; 
    TextureCached = true; 
} 
void ListenForUpdate(){ 
    // Simulate waiting for an asynchronous update notifying us of the updated texture. 
    Thread.Sleep(1000); 

    // ...Receive some notification image is ready load. 


    // In my case, I'm just loading a local file for testing. 
    TexturePath = @"file://C:\Users\Public\Pictures\LargeAssPicture.jpg"; 
    TextureLoadReady = true; 
} 

/// <summary> 
/// Create a temporary copy of maintexture so that SetPixel doesn't overwrite the original 
/// </summary> 
void SwapMainTexture(){ 
    Texture2D texture = (Texture2D)Instantiate(renderer.material.mainTexture); 
    renderer.material.mainTexture = texture; 
} 

/// <summary> 
/// Update the main texture in small chunks (<MaxPixelConvert) 
/// </summary> 
void ImABadIdea(){ 
    int count = 0; 
    Texture2D main_texture = (Texture2D)renderer.sharedMaterial.mainTexture; 
    for(int x = (int)last_pixel.x; x <= cached_texture.width; x++){ 
     for(int y = (int)last_pixel.y; y <= cached_texture.height; y++){ 
      main_texture.SetPixel(x,y,cached_texture.GetPixel(x,y)); 
      last_pixel = new Vector2(x,y); 

      if(y+1>=cached_texture.height)last_pixel.y = 0; 
      count += 1; 
      if(count >= MaxPixelConvert)break; 
     } 
     if(count >= MaxPixelConvert)break; 
    } 
    main_texture.Apply(); 

    if(last_pixel.x == cached_texture.width && last_pixel.y == cached_texture.height){ 
     TextureLoaded = true; 
    } 
} 

void Update() { 
    if(TextureLoadReady){ //trigger when new texture ready to load 
     TextureLoadReady = false; 
     StartCoroutine(ReadNewTexture()); 
    } 
    if(TextureCached && !TextureLoaded){ //trigger when new texture is loaded and start streaming it 
     ImABadIdea(); 
    } 
} 

的紋理加載由觸發簡單的工作線程。當線程「接收」加載新紋理的通知時,會設置相應的標誌(我知道我沒有鎖定共享資源,但我的例子很簡單)。之後,紋理被輸入到一個緩存中,然後逐漸應用到我的對象的紋理中,每個幀在主線程中打勾,並以小的1000px塊爲單位。

在我的測試場景中,我有我的主要對象,然後克隆了那個仍然隱藏在屏幕外的對象。該克隆具有該腳本並將加載新紋理。當紋理加載後,我將它換入主對象。

代碼在3000x3000像素圖像上進行測試。

0

如果以某種方式使用紋理,它會上傳到顯卡。因此,在遊戲的加載屏幕中,您只需循環所有要「預加載」的紋理,並以某種方式使用它們,例如將它們渲染到RenderTexture,或使用GUI.DrawTexture將它們繪製到屏幕(然後在上面繪製加載屏幕背景)。

0

負荷您的資源文件夾

Renderer objectRenderer; 
 
public Texture2D replacementTextureAsset; 
 
Texture2D runtimeTextureReplacement; 
 

 
void Awake() 
 
{ 
 
    objectRenderer = (Renderer)GetComponent(typeof(Renderer)); 
 

 
    // Either have the texture assigned via the inspector (replacementTextureAsset above) 
 
    // or else get a reference to it at runtime. Either way, the texture will be loaded into memory by the end of this loop. 
 
    runtimeTextureReplacement = Resources.Load("myReplacementAsset"); 
 
} 
 

 
void TextureReplace() // Called whenever 
 
{ 
 
    objectRenderer.material.maintexture = replacementTextureAsset; 
 
}

0

質地可能是它`不冷靜,但在Unity 5.3工作。 在喚醒/啓動場景/ monobehaviour上調用您希望紋理預加載的每個遊戲對象的擴展方法。

public static class GameObjectExtension 
    { 
     public static void PreloadTexture(this GameObject go) 
     { 
      var render = go.GetComponentInChildren<Renderer>(); 
      if (render && render.sharedMaterial && render.sharedMaterial.mainTexture) 
      { 
       int dd = render.sharedMaterial.mainTexture.width; 
      } 
     } 
    } 

here.