2013-01-08 17 views
5

Modyfikuję materiał, który jest stosowany do obiektu, zmieniając jego teksturę, ale problemem jest to, że podczas tego procesu odczuwam pewne opóźnienie.Wstępne ładowanie tekstur w unity3d

W jaki sposób mogę wstępnie załadować niektóre tekstury w pamięci, aby uniknąć czasowego opóźnienia w unity3d?

+0

ten jest bardzo podobny do swojego postu [inny] (http://stackoverflow.com/questions/13974108/load-materials-on-objects-in-async- metody). – Jerdak

+0

@Jerdak nie, nie, w tym poście byłem zainteresowany załadowaniem zdjęć w asynchronizacji. W tym interesuję się wstępnym ładowaniem obrazów. – Alex

Odpowiedz

4

Czy ładujesz teksturę tuż przed dodaniem? Jak przechowywane są nowe tekstury? Zazwyczaj buforowanie wstępne jest wykonywane podczas pętli Przebudźcie się() lub 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; 
} 

Jeśli to, co masz już robi i nadal masz „lag”, a następnie pewnie doświadczyć nieuniknioną konsekwencją wysłania faktury do bufora ramki na karcie graficznej. W takim przypadku nic nie możesz zrobić, oprócz użycia mniejszej tekstury.

0

dałem swoje pytanie trochę więcej myśli i tutaj jest moja propozycja, to hacky i żałuję, że nie trzeba było skojarzyć ten kod z moim nazwiskiem:

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(); 
    } 
} 

Obciążenie tekstura jest wyzwalane przez prosty wątek roboczy. Kiedy wątek "odbiera" powiadomienie o nowej fakturze do załadowania, ustawia odpowiednią flagę (wiem, że nie blokuję wspólnych zasobów, ale mój przykład jest wystarczająco prosty). Następnie tekstura jest przesyłana do pamięci podręcznej, a następnie stopniowo nakładana na strukturę obiektu w małych kawałkach o wielkości 1000 pikseli, każda klatka zaznacza się wewnątrz głównego wątku.

Na mojej scenie testowej miałem mój główny obiekt, a następnie klon tego obiektu, który pozostał ukryty poza ekranem. Klon miał skrypt i ładował nową teksturę. Po załadowaniu tekstury zamieniłem ją na główny obiekt.

Kod został przetestowany na obrazie o wymiarach 3000x3000 pikseli.

0

Jeśli użyjesz tekstury w jakiś sposób, zostanie ona przesłana na kartę graficzną. Tak więc, podczas ładowania ekranu gry, musisz po prostu przejrzeć wszystkie tekstury, które chcesz "wczytać" i użyć ich w jakiś sposób - na przykład renderując je do RenderTexture lub używając GUI.DrawTexture, aby narysować je do ekranie (a następnie narysuj tło ekranu ładowania na górze).

0

załadować tekstury w folderze zasobów

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

Może być `s nie fajne, ale to działa w Unity 5.3. Wywołanie tej metody rozszerzenia w obudzić/rozpocząć scenę/monobehaviour na każdym obiekcie gry, który chcesz wstępnie załadować tekstury.

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; 
      } 
     } 
    } 

Pomysł pochodzi z here.

Powiązane problemy