How do you efficiently display a large number of user-selected images?

I’m trying to learn Unity with a simple project, so I’m creating an image viewer. The basic idea is that you can point to a folder of images at runtime and view the images in it. I have the basic functionality working using the streamingAssets folder for storing the test images, which are retrieved with WWW and displayed with a RawImage component.

Currently, the script just loads all images in the folder into objects at Start(), before displaying anything. Obviously this is not a good long-term solution for images that will be displayed one at a time, but that’s a separate issue. To understand how good/bad this system is, I put 150 fairly large images in the test folder, which add up to about 350MB.

At runtime (both in editor or standalone build), according to the profiler, the textures take up 5.6GB of memory and the objects take 2.9GB. Additionally, it writes about 4GB to my hard drive, which is cleared on quit, but I have absolutely no idea where that’s coming from (checked the Data folder, and all of AppData, nowhere to be found).

This is the code I’m using to load images, in case there’s anything obvious I missed:

private void LoadImages(string imagesLocation)
    {
        imagePaths = Directory.GetFiles(imagesLocation, "*")
            .Where(s => s.EndsWith(".png") || s.EndsWith(".jpg")).ToArray<string>();

        foreach (string imagePath in imagePaths)
        {
            WWW img = new WWW("file:///" + imagePath);
            Image temp = new Image(
                Path.GetFileNameWithoutExtension(imagePath),
                img.texture,
                imagePath);
            m_imagesList.Add(temp);
        }
    }

So to be clear, my main question is:

  1. What is generally the best way to load and display a large number of images in Unity, but also:
  2. Is Unity writing to the hard drive, or is that a normal Windows feature when you abuse your RAM?
  3. Is it better to use RawImage or Sprites (or something else?) for UI images that will only be used in UI and will be displayed for an arbitrary amount of time, and may be displayed multiple times?

Since this question got so many followers and no answers, I’ll try and share the information I found scattered across many other questions and docs, although I don’t feel confident that it’s a complete 100% answer, it’s much better than yet another person finding their question with 0 answers. (apologies for the formatting, I cannot make this thing create blank lines no matter how many spaces I use)

Question 1: What’s the best way to load and display a large number of images at runtime in Unity?


I’m not entirely sure what the perfect answer is, but I’m trying to avoid spending a year searching for the holy grail of image loading, so here are some partial answers to apply to various situations.

  1. Loading: The part in my example code that uses .Where() was copied from this question, and it works fine. Problem 1 is mentioned there, that the method goes through all the files in the folder, then filters them later, which is a waste of time. Problem 2 is that it (if I understand correctly) uses a closure, which Unity hates for reasons I don’t fully understand. It’s a small thing, but it seems better to just create two string arrays and concatenate them.
  2. Loading: This example loads all the files at one time, which is obviously horrible if you have a lot of images, or very large images. Of course the solution there depends on what you’re doing, so you may break up the load to a few at a time, or as needed, or whatever. Either way, it should be a coroutine so it doesn’t stop the program from responding. (Video tutorial)
  3. Compression: Unity uses textures to display images, since it’s originally a 3D graphics engine. RawImage is used to display PNG and JPG files, but it still needs a texture to do so. The important thing to know here is that textures are just much larger files than normal images, so using uncompressed versions is extremely costly. WWW.texture generates a texture from the image, but does not compress it. Also, depending on your code, there’s a chance the texture will stick around in memory if there’s still a reference to it, so you need to use WWW.dispose() to be sure. If you already have a compressed texture on your gameobject, WWW.LoadImageIntoTexture() will compress your image as it’s creating the texture and loading it into the object. If you don’t have a compressed image in there, you can create one before loading: public Texture2D img = new Texture2D(100, 100, TextureFormat.DXT1, false); That creates a 100x100 texture compressed into DXT1 format, with no mipmap (since it’s a flat UI image).
  4. Compression: If you don’t want to use WWW for some reason, you can use ImageConversion.LoadImage, which is what WWW.LoadImageIntoTexture() calls anyway. Alternately, you can use Texture2D.compress() if you’re okay with creating uncompressed textures and compressing them later.
  5. Compression: If you’re loading random images, be aware that Unity prefers dimensions which are a power of two on each side. Images with other sizes will be slightly larger. See here and here.

Question 2: Why is Unity taking up hard drive space at runtime?

I knew the answer to this but could not for the life of me remember what it was called. Paging is when RAM is written to storage. Once I remembered the name, I was able to confirm it was just Windows expanding pagefile.sys to accommodate my horrible Unity code combined with my horrible Chrome tab hoarding.

Question 3: Sprites vs RawImage in Unity

I wanted to come back here with some more concrete numbers to add to this, but I haven’t had the time to set up a proper test and make a fancy spreadsheet. In summary, as the Unity docs say, each RawImage creates an extra draw call, so it’s bad for your framerate. Sprites will be faster but they aren’t magic.