【问题标题】:preload textures in unity3d在unity3d中预加载纹理
【发布时间】:2016-11-26 12:14:05
【问题描述】:

我正在修改应用于对象的材质,方法是更改​​其纹理,但问题是我在执行此操作时会出现一些延迟。

如何在内存中预加载一些纹理以避免 unity3d 中的时间延迟?

【问题讨论】:

  • 这和你的other post非常相似。
  • @Jerdak 不,不是,在那篇文章中我对异步加载图像感兴趣。在这方面,我对预加载图像很感兴趣。

标签: unity3d


【解决方案1】:

您是否在添加纹理之前立即加载纹理?新纹理是如何存储的?通常,预缓存是在 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;
}

如果这是您已经在做的事情并且您仍然有“滞后”,那么您可能会遇到将纹理发送到显卡上的帧缓冲区的必然结果。在这种情况下,您只能使用较小的纹理。

【讨论】:

    【解决方案2】:

    我对你的问题做了更多思考,这是我的建议,它很老套,我希望不必将此代码与我的名字相关联:

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

    纹理加载由一个简单的工作线程触发。当线程“接收”要加载的新纹理的通知时,它会设置适当的标志(我知道我没有锁定共享资源,但我的示例很简单)。之后,纹理被放入缓存中,然后在主线程中的每帧滴答声中以 1000 像素的小块逐渐应用于我的对象的纹理。

    在我的测试场景中,我有我的主要对象,然后是该对象的一个​​克隆,它仍然隐藏在屏幕外。克隆有脚本并且会加载新的纹理。加载纹理后,我将其换成主要对象。

    代码在 3000x3000 像素的图像上进行了测试。

    【讨论】:

      【解决方案3】:

      如果您以某种方式使用纹理,它会被上传到显卡。因此,在游戏加载屏幕期间,您只需要遍历所有要“预加载”的纹理,并以某种方式使用它们——例如将它们渲染到 RenderTexture,或使用 GUI.DrawTexture 将它们绘制到屏幕(然后在顶部绘制加载屏幕背景)。

      【讨论】:

        【解决方案4】:

        可能不是很酷,但它适用于 Unity 5.3。 在要预加载纹理的每个游戏对象的唤醒/开始场景/单行为中调用此扩展方法。

        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.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-30
          • 1970-01-01
          • 2015-09-18
          • 2013-03-27
          • 1970-01-01
          • 2016-06-11
          相关资源
          最近更新 更多