2013-01-08 129 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.