Texture only loads correctly after restart or re-import

Hey guys,

Not sure if this is the right subforum, but I wasn’t sure where else to put it.

Basically, I’ve got an image, the pixel data of which I use to create certain objects. It’s a larger version of this one (basically a rough map of city-states of ancient Greece):

Of course, it has read/write enabled, filter mode point and compression none.

Now when I run this project straight after starting Unity, everything works as intended. On any subsequent runs, the project gave all kinds of errors. After a bit of debugging I think I’ve found the error, and frankly it baffles me. To test it, I’ve written the following code:

Texture2D map = Map.singleton.cityMap;
byte[] _bytes = map.EncodeToPNG();
System.IO.File.WriteAllBytes("testMAP.png", _bytes);

(The first line is just loading the texture, the next two lines are for testing.)

Now, after reloading the project (or, as I later found out, re-importing the texture), the resulting testMap.png looks exactly like the image above. If I run my code again without re-importing, however, testMap.png looks like this:

The image is suddenly flipped and the colours are all wrong?!

Of course, the base image is still the same.

I’ve checked my code, and nowhere do I write to that texture, in fact, the only functions/properties I use on it are GetPixel and getting its width and height. I also wrote the image to disk after calling those functions, and it makes no difference, the result is still right or wrong depending on if I re-imported it. Now why would this image only load correctly right after import? If it loads correctly the first time, and I don’t make any changes to it, why doesn’t it load correctly any subsequent times? Is there any obscure setting I might have missed? Is this a bug? Is there something else going on? :face_with_spiral_eyes:

Thanks in advance for any help!

Hey @df3852 ,

Can you try to use the same texture on a completely empty project, to see if it also requires reimporting every time?

If in a new project, the texture is working fine, you can start adding the scripts/libraries that are currently accessing/modifying such texture on your original project in order to find the root of the issue.

Good luck with it!

1 Like

Thank you for your help. I didn’t need to create an empty project in the end, but your post did help to “go back to the basics” for a bit and go through all references to the texture asset (I feel such a noob for not doing so in the first place:sweat_smile:). It turned out the problem was in some half-forgotten script that was mistakenly assigned that texture asset instead of a different one. This script does a bunch of SetPixel operations on a Texture2D - once I assigned it a different Texture2D asset it worked again.

However, I do wonder if this is intended behaviour. Nothing is written to the file after all, so shouldn’t the asset be reloaded from disk on a restart, rather than taking the changed image from cache? I cannot really think of any situation where it makes sense to load an image along with all the changes of a previous run unless a user has explicitly written these changes back to disk. Perhaps it would make more sense to disable the cache on images where read/write is enabled?

1 Like

First of all, I’m glad that you found the solution to your current situation.

On the other hand, if you want to have the changes reset once you exit your game/app you should duplicate the original texture and make the changes on the duplicated texture instead of the original.

You can see how you can do it on the example of the SetPixels documentation: Unity - Scripting API: Texture2D.SetPixels

I hope this helps!

Yeah, I meant to do it on a different file, but by mistake dropped an already used file in there.

However, your reply is not entirely correct in that the changes do reset when exiting the app, as the image is not written to disk. I think this case exposes an instance of different behaviour between Unity and the resulting game/app.

Let’s say that in a hypothetical app you load an entirely white texture white.png and then do some SetPixel operations, followed by an Apply after which the app exits:

public class ExampleClass : MonoBehaviour
{
    public Texture2D tex; //white.png will be assigned in the editor
    void Start()
    {
        //tex will be completely white when running as standalone, but have a black pixel when restarting in unity.
        tex.SetPixel(0, 0, Color.black);
        tex.Apply();
        //do fancy things with tex.
        Application.Quit();
    }
}

If restarting the resulting standalone app, white.png will load from disk, and hence be completely white, as is the original. However, if restarting the app from within Unity, the texture is loaded from cache and hence results in a black pixel. This is different behaviour between Unity and the standalone app. I therefore wonder if it isn’t better to either invalidate the cache on an application quit for textures that have read/write enabled, or at the least mention it in the Documentation.

Sorry for the confusion. The original asset will remain unchanged while executing your code (with some exceptions in where you explicitly access the original file path and change it intentionally).

During the importing and re-importing process, Unity reads and processes any files that you add or change in the Assets folder, converting the contents of such files to internal game-ready data. The asset files themselves remain unchanged, and the internal data is stored in the project’s Library folder.

Using internal formats for assets allows Unity to have game-ready versions of your assets ready to use at runtime in the Editor while keeping your unmodified source files in the Assets folder. Keeping the internal formats separate from the asset files means that you can quickly edit them and have the Editor pick up the changes automatically.

The one that is changed during the execution of your code is the game-ready file, which it’s the one placed on the Libray, not in the Cache :wink:

You can read more about it here: Unity - Manual: Asset workflow

I hope this helps!