[Solved] About an inefficiency when reading textures

When working on custom editors in Unity, it is common to read textures to create new ones or apply various modifications to existing textures.

However, the dilemma with handling textures often revolves around the isReadable setting. In the editor, repetitive tasks can lead to inefficiencies, as you have to repeatedly load the importer, set the texture to be readable, save it, perform your work, and then set isReadable back to false before saving again. This process can be very time-consuming and often becomes the most time-intensive part of working with custom editors.

Setting textures to be not readable is essential for optimization, but maintaining this state in the editor is inefficient. Of course, if you maintain all textures to isReadable and then set them back to false only when building, the build time will be overwhelmingly longer.

To address this issue, I propose adding a flag called isReadableInEditor, which would be set to true by default, allowing textures to be read directly in the editor. While implementing this feature would require additional disk space, its impact would only affect the editor environment. Considering the time savings from repetitive tasks, the benefits of this feature would far outweigh the costs.

You can also just make a readable version and throw it away:

1 Like

This Stack Overflow post is about how to handle textures written in code at runtime. It’s completely off topic. I’m talking about handling textures in the editor.

Is it? You wrote this originally:

With the above code snippet, load the texture (NOT readable), make a readable copy, use that, discard that temporary texture.

I see. I only read part of your post and made a hasty judgment. I apologize to you. This method definitely improves a lot of the performance of setting textures to readable and then back again.

1 Like

This code uses a fixed color space of Linear, which can cause some textures to appear differently than intended. I added a small fix for this.

        Texture2D duplicateTexture(Texture2D source)
        {
            RenderTexture renderTex = RenderTexture.GetTemporary(
                source.width,
                source.height,
                0,
                RenderTextureFormat.Default,
                source.isDataSRGB ? RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear);
            
            Graphics.Blit(source, renderTex);
            RenderTexture previous = RenderTexture.active;
            RenderTexture.active = renderTex;
            Texture2D readableText = new Texture2D(source.width, source.height);
            readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
            readableText.Apply();
            RenderTexture.active = previous;
            RenderTexture.ReleaseTemporary(renderTex);
            return readableText;
        }

Also, if someone want to use the texture copied with this method as a normal map, you need to set the imported texture’s format to Default to use it as a NormalMap. Otherwise, you will get distorted results.

If you want to copy the colors completely while keeping the import format as NormalMap, you need to use the texture importer to save the texture’s format as Default, and then read the texture again. In this case, the inefficiency problem I raised at the beginning occurs again. There may be a way to change the pixel values ​​from the format of NormalMap to the format of Default, but I haven’t looked into it yet.