Search Unity

Generate mipmaps at runtime for a texture loaded with UnityWebRequest?

Discussion in 'General Graphics' started by tatea, Mar 15, 2019.

  1. tatea

    tatea

    Joined:
    Sep 1, 2015
    Posts:
    8
    How can I generate mipmaps for a texture loaded from UnityWebRequest at runtime? Please note while I use 'www' as a reference, it is not using the WWW class.

    I'm currently loading a texture from a UnityWebRequest using this code:

    Code (CSharp):
    1. IEnumerator DownloadImage()
    2.    {
    3.        string url = videoThumbnailURL;
    4.        UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
    5.        DownloadHandler handle = www.downloadHandler;
    6.  
    7.        yield return www.SendWebRequest();
    8.        if (www.isHttpError || www.isNetworkError)
    9.        {
    10. //do my error stuff
    11.        }
    12.        else
    13.        {
    14.            //Load Image
    15.            Texture2D texture2d = DownloadHandlerTexture.GetContent(www);
    16.  
    17.            Sprite sprite = null;
    18.            sprite = Sprite.Create(texture2d, new Rect(0, 0, texture2d.width, texture2d.height), Vector2.zero);
    19.  
    20.            if (sprite != null)
    21.            {
    22.                videoThumbnailImage.sprite = sprite;
    23.            }
    24.        }
    25.    }

    Which loads the texture but obviously doesn't generate mipmaps. I've tried using
    Code (CSharp):
    1. texture2d.SetPixels(texture2d.GetPixels(0, 0, texture2d.width, texture2d.height));
    2. texture2d.Apply(true);

    .. per an old Unity forum discussion but that didn't seem to work. Any thoughts?
     
  2. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,582
    If you do the "texture2d.Apply(true);" it should generate mipmaps... or at least that was my understanding.
     
  3. tatea

    tatea

    Joined:
    Sep 1, 2015
    Posts:
    8
    I've tried adding that below line 15 like this but it didn't work.
    Code (CSharp):
    1. //Load Image
    2. Texture2D texture2d = DownloadHandlerTexture.GetContent(www);
    3. texture2d.SetPixels(texture2d.GetPixels(0, 0, texture2d.width, texture2d.height));
    4. texture2d.Apply(true);
     
  4. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,582
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    6,994
    Try adding this line after the GetContent() call:
    Code (csharp):
    1. Debug.Log("MipMap Count = " + texture2d.mipmapCount);
    If that prints 0 into the log, then the Texture2D that GetContent is creating does not have mip maps enabled, so nothing you do after that will make it work as there's no way to enable mipmaps post creation of the Texture2D object. You'll likely need to do something like this:

    Code (csharp):
    1. Texture2D wwwTex = DownloadHandlerTexture.GetContent(www);
    2. Texture2D newTex = new Texture2D(wwwTex.width, wwwTex.height);
    3. newTex.SetPixels(wwwTex.GetPixels(0));
    4. newTex.Apply(); // default is to update mipmaps
    You could also use newTex.Resize(wwwTex.width, wwwTex.height); and reuse the "newTex" Texture2D rather than creating a new one every time.
     
    tatea and MD_Reptile like this.
  6. cdytoby

    cdytoby

    Joined:
    Nov 19, 2014
    Posts:
    144

    loadedTexture = new Texture2D(wwwTexture.width, wwwTexture.height, wwwTexture.format, true);
    loadedTexture.LoadImage(uwr.downloadHandler.data);


    I use dynamic load texture with mipmap in our main project and this works on my side.

    wwwTexture is the texture you get from UnityWebRequest uwr, and loadedTexture is a new Texture2D, which is also the result texture with mipmap.

    SetPixel should not be needed, at least not on my side. You may want to call Apply().
     
    Last edited: Mar 15, 2019
    MD_Reptile and bgolus like this.
  7. tatea

    tatea

    Joined:
    Sep 1, 2015
    Posts:
    8

    Thank you all for the help - this solution worked for me!
     
  8. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,232
    Hey, please note, there is Graphics.CopyTexture API which is much more effective than Get\SetPixels or LoadImage, when supported.

    Here is an example:

    Code (CSharp):
    1. if (SystemInfo.copyTextureSupport != CopyTextureSupport.None)
    2. {
    3.     Graphics.CopyTexture(wwwTexture, 0, 0, mipTexture, 0, 0); // copies mip 0
    4. }
    5. else
    6. {
    7.     mipTexture.LoadImage(www.downloadHandler.data);
    8. }
    9.  
    10. mipTexture.Apply(true); // generates all other mips from mip 0
    In my case, Get\SetPixels() took ~64k ticks, LoadImage took ~34k ticks, where Graphics.CopyTexture took only ~8k ticks.
     
    MD_Reptile likes this.
  9. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,582
    Ok, whoa. Your blowing my mind right now. I went with a compute shader because it performed way better than getpixel and setpixel apply methods - but if what you say is true, then compatibility would be way better across more devices. I'm going to experiment with this, so thanks so much for sharing!