簡體   English   中英

在unity3d中預加載紋理

[英]preload textures in unity3d

我正在通過改變其紋理來修改應用於對象的材質,但問題是我在執行此操作時會遇到一些延遲。

如何在內存中預加載一些紋理以避免unity3d中的時間滯后?

在添加紋理之前是否正在加載紋理? 新紋理是如何存儲的? 通常,預緩存是在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;
}

如果這是你已經在做的並且你仍然有“滯后”,那么你可能會遇到將紋理發送到圖形卡上的幀緩沖區的不可避免的后果。 在這種情況下,除了使用較小的紋理外,你無能為力。

我更多地考慮了你的問題,這是我的建議,這是hacky,我希望我沒有必要將這段代碼與我的名字聯系起來:

    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像素圖像上進行了測試。

如果以某種方式使用紋理,它將被上傳到圖形卡。 因此,在游戲的加載屏幕中,您只需要遍歷所有想要“預加載”的紋理,並以某種方式使用它們 - 例如將它們渲染為RenderTexture,或使用GUI.DrawTexture將它們繪制到屏幕(然后在頂部繪制加載屏幕背景)。

可能它不酷,但它適用於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;
            }
        }
    }

這個想法來自這里。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM