Default import rules for modifying pasted pictures in Unity3D editor

Posted by guilhenfsu on Wed, 01 Dec 2021 17:36:57 +0100

After the map is imported into unity, it will be automatically set to compression format. It will first judge whether the map has transparent channels.
Android: compressed into ETC1 without transparent channel, compressed into ETC2 with transparent channel, and not divided by 4. fall back to RGBA32
IOS: compressed into RGB PVRTC without transparent channel and RGBA PVRTC with transparent channel, which is not an integer power of 2, fall back to RGBA32
When a Texture picture is dragged in, as shown in the figure below, unity will set ToNerest by default, which will automatically ensure that the picture on Android platform is divided by 4, and the picture on IOS platform is divided by 2, so the picture can be compressed best by default.

However, if you are making UGUI, because you need to set the Texture to Sprite, it will not be ToNearest, which will lead to a problem. It is difficult for art students to ensure that the size of the picture is an integer power of 2, so it can not be compressed under IOS.
Through the above question, I want to do one thing is to automatically set the optimal format of the UI image when it is dragged into the unit. (the optimal solution is only used in the large graph mode, that is, the graph with length and width exceeding 128 at one time and 64 at the other side is not suitable to be placed in the graph set)
1. Although it is difficult for art students to ensure that the picture is an integer power of 2, it is easy to ensure that the picture can be divided by 4, so I will ask them to provide pictures that must be divided by 4.
2. The format of ETC+Crunched is preferred to set the picture rules under Android. If the picture cannot be divided by 4, the ASTC format is set. If the Android phone does not support ASTC, it will fall back to RGBA32
3. PVRTC4 is used as the priority setting rule under IOS. If the picture is not an integer power of 2, the ASTC format is set. If fall back to RGBA32 is not supported
4. We only provide the best scheme for importing pictures for the first time, which can be modified later. For example, a picture divided by 4 and with ALPHA will be automatically set to ETC2+Crunched format after importing according to this rule, but if the art students think the effect is not good, they can modify it to ASTC RGBA 4X4 or RGBA32 later
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
 
public class ImportPicture : AssetPostprocessor
{
 
    void OnPreprocessTexture()
    {
        TextureImporter importer = assetImporter as TextureImporter;
        if (importer != null)
        {
            if (IsFirstImport(importer))
            {
                importer.textureType = TextureImporterType.Sprite;
                TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("iPhone");
                bool isPowerOfTwo = IsPowerOfTwo(importer);
                TextureImporterFormat defaultAlpha = isPowerOfTwo ? TextureImporterFormat.PVRTC_RGBA4 : TextureImporterFormat.ASTC_RGBA_4x4;
                TextureImporterFormat defaultNotAlpha = isPowerOfTwo ? TextureImporterFormat.PVRTC_RGB4 : TextureImporterFormat.ASTC_RGB_6x6;
                settings.overridden = true;
                settings.format = importer.DoesSourceTextureHaveAlpha() ? defaultAlpha : defaultNotAlpha;
                importer.SetPlatformTextureSettings(settings);
 
                settings = importer.GetPlatformTextureSettings("Android");
                settings.overridden = true;
                settings.allowsAlphaSplitting = false;
                bool divisible4 = IsDivisibleOf4(importer);
                defaultAlpha = divisible4 ? TextureImporterFormat.ETC2_RGBA8Crunched : TextureImporterFormat.ASTC_RGBA_4x4;
                defaultNotAlpha = divisible4 ? TextureImporterFormat.ETC_RGB4Crunched : TextureImporterFormat.ASTC_RGB_6x6;
                settings.format = importer.DoesSourceTextureHaveAlpha() ? defaultAlpha : defaultNotAlpha;
                importer.SetPlatformTextureSettings(settings);
            }
        }
    }
    //Divide by 4
    bool IsDivisibleOf4(TextureImporter importer)
    {
        (int width, int height) = GetTextureImporterSize(importer);
        return (width % 4 == 0 && height % 4 == 0);
    }
 
    //Integer power of 2
    bool IsPowerOfTwo(TextureImporter importer)
    {
        (int width, int height) = GetTextureImporterSize(importer);
        return (width == height) && (width > 0) && ((width & (width - 1)) == 0);
    }
 
    //The map does not exist, the meta file does not exist, and the picture size has been modified. You need to import it again
    bool IsFirstImport(TextureImporter importer)
    {
        (int width, int height) = GetTextureImporterSize(importer);
        Texture tex = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
        bool hasMeta = File.Exists(AssetDatabase.GetAssetPathFromTextMetaFilePath(assetPath));
        return tex == null || !hasMeta || (tex.width != width && tex.height != height);
    }
 
    //Gets the width and height of the imported picture
    (int, int) GetTextureImporterSize(TextureImporter importer)
    {
        if (importer != null)
        {
            object[] args = new object[2];
            MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);
            mi.Invoke(importer, args);
            return ((int)args[0], (int)args[1]);
        }
        return (0, 0);
    }
}

Here, we will first judge whether the DoesSourceTextureHaveAlpha image has a transparent channel and select the corresponding optimal solution. Another problem here is that generally, we need to put the large image of the UI in the specified directory, that is, the above code should only process the images in the specified directory. You can judge the path, but another problem will arise. First, put the picture into the unit, and then move the picture to the UI directory just specified. If this is the case, OnPreprocessTexture in the above code will not be executed. Therefore, we need to listen to the success event of resource import. If it is moved to the UI directory, we need to re import the asset.

static bool forceImport = false;
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        foreach (string str in movedAssets)
        {
            if (str.Contains("UI Save path"))
            {
                forceImport = true;             //reimport and force IsFirstImport
                AssetDatabase.ImportAsset(str); // If you are moving to the specified UI directory, you need to Import again
            }
        }
    }

Article source: https://www.yxkfw.com/thread-69943-1-1.html

 

Topics: Java Unity Programmer WPF