国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

這篇具有很好參考價(jià)值的文章主要介紹了【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

功能介紹:

1. 壓縮工具支持對圖片原文件壓縮(支持png/jpg),也支持使用Unity內(nèi)置圖片壓縮批量對圖片設(shè)置壓縮參數(shù)。

2. 支持以文件夾或及其子文件夾為單位批量生成圖集(SpriteAtlas), 支持同時(shí)生成圖集變體(SpriteAtlas Variant),支持忽略像素寬高大于限定值的圖片打進(jìn)圖集。

3. 批量給現(xiàn)有圖集(SpriteAtlas)生成圖集變體,生成圖集變體后可以調(diào)整圖集的縮放

4. 動(dòng)畫壓縮,降低animation clip序列化文件的浮點(diǎn)型精度,保留較少的小數(shù)以降低文件大小。

工具預(yù)覽:

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

工具完整代碼參見開源框架GF_HybridCLR


圖片無疑是游戲資源大戶,無論數(shù)量還是文件大小占比都非常高。使用TinyPng等壓縮工具壓縮,近乎瘋狂的壓縮比,通常可以將圖片文件大小降低70%左右。

對于Cocos2d-x時(shí)代的項(xiàng)目通常都會(huì)使用TinyPng進(jìn)行圖片壓縮。

然而對于Unity來說,壓縮圖片雖然能大幅降低圖片文件大小,但是最終打出的包(AssetBundle或Addressables)文件大小并不會(huì)明顯降低,甚至?xí)葔嚎s圖片前還大。這是因?yàn)閁nity針對不同平臺(tái)都有對應(yīng)的圖片壓縮模式,無論你再怎么壓縮,Unity導(dǎo)入圖片或打包時(shí)都會(huì)再次使用對應(yīng)平臺(tái)的壓縮方式重新壓縮圖片,這就導(dǎo)致在圖片分辨率不變的情況下,最終打包后的資源大小并不能有效降低。

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮
OpenAI的問答結(jié)果

但是。。。沒錯(cuò),還有但是,對于龐大的項(xiàng)目來說,合理壓縮圖片原文件可以有效降低工程大小,提高打開工程的加載速度等。然后通過工具的Unity內(nèi)置圖片壓縮批量操作可以快速方便設(shè)置圖片壓縮參數(shù)。

AssetBundle提供了LZ4和LZMA兩種壓縮方式:

LZ4: 壓縮/解壓較快,壓縮后的文件大。適用于在線壓縮/解壓、網(wǎng)絡(luò)數(shù)據(jù)等需要頻繁壓縮/解壓的情況。

LZMA: 壓縮/解壓較慢,壓縮后的文件小。適用于對文件大小要求高,且不頻繁壓縮/解壓的情況。

以上兩種壓縮再結(jié)合GF的額外壓縮,又能進(jìn)一步降低包體大小。當(dāng)然,也需要根據(jù)需求平衡文件加載速度和文件資源大小的取舍。

模式一:圖片原文件壓縮模式

一,圖片原文件壓縮工具功能設(shè)計(jì):

?1. 壓縮算法的選擇:

tinypng在線壓縮 + pngquant和ImageSharp離線壓縮:

tinypng壓縮比極高,支持png/jpg/webp, 并且提供了包括.Net的多種編程語言API支持,適合做批處理。但是,tinypng需要上傳圖片到服務(wù)器,壓縮完后還要下載壓縮后的圖片。圖片較大較多時(shí)處理過程會(huì)巨慢。如果有離線壓縮算法就完美了,離線壓縮庫使用的是pngquant和ImageSharp,都是開源壓縮算法:

pngquant: 只支持png壓縮,對png的壓縮比接近tinypng;也可從官網(wǎng)可以下載命令行工具,支持windows和mac;

ImageSharp:C#實(shí)現(xiàn),跨平臺(tái)。對jpg的壓縮比tinypng還要好。

Tinypng API :?TinyPNG – API Reference

?2. 添加需要壓縮的文件/文件夾,并在列表中顯示已經(jīng)添加的文件/文件夾,支持添加/刪除:

如上圖,用戶可以點(diǎn)擊列表的"+"號(hào)彈出Unity自帶的資源選擇界面(支持選擇文件夾/圖片文件),

但是Unity自帶選擇界面僅支持單選,所以還需要做個(gè)拖拽功能以支持批量添加。

3. 壓縮設(shè)置項(xiàng):

對于tinypng,需要注冊序列號(hào),每個(gè)序列號(hào)可以免費(fèi)壓縮500張。可以一次配置多個(gè)序列號(hào),壓縮時(shí)取首行序列號(hào)。

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

離線壓縮:對于png格式,勾選離線壓縮后使用pngquant本地壓縮。

覆蓋原圖片:勾選后壓縮后的圖片直接覆蓋原圖。

壓縮質(zhì)量(僅對pngquant離線壓縮有效):為區(qū)間數(shù)值(min, max),當(dāng)壓縮質(zhì)量小于min時(shí)則不對該圖片壓縮,其實(shí)就是為了把圖片控制在一定質(zhì)量范圍,不至于太糊。

快壓等級:等級越高,壓縮處理速度越快,但壓縮比隨之小幅降低。一般為了極致壓縮比會(huì)把快壓等級調(diào)到最低。

輸出路徑:壓縮后的圖片存放路徑。

備份路徑:點(diǎn)擊備份會(huì)自動(dòng)把當(dāng)前選擇的原圖備份到指定目錄,以便后續(xù)還原需求。

4. 功能:

功能按鈕包含壓縮、備份、還原、保存當(dāng)前設(shè)置。

二,功能實(shí)現(xiàn):

下載tinypng壓縮庫:可以在Visual Studio的NuGet中搜索下載tinypng庫,然后把dll放入U(xiǎn)nity工程。

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

?下載pngquant命令行版(有Window,Mac版本),放入U(xiǎn)nity工程。

1. tinypng在線壓縮:

/// <summary>
    /// 使用TinyPng在線壓縮,支持png,jpg,webp
    /// </summary>
    private async Task<bool> CompressOnlineAsync(string imgFileName, string outputFileName)
    {
        if (string.IsNullOrWhiteSpace(TinifyAPI.Tinify.Key))
        {
            return false;
        }

        var srcImg = TinifyAPI.Tinify.FromFile(imgFileName);
        await srcImg.ToFile(outputFileName);
        return srcImg.IsCompletedSuccessfully;
    }

?2. pngquant和ImageSharp本地壓縮:

/// <summary>
        /// 使用ImageSharp壓縮jpg圖片
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <returns></returns>
        private static bool CompressJpgOffline(string imgFileName, string outputFileName)
        {
            using (var img = SixLabors.ImageSharp.Image.Load(imgFileName))
            {
                var encoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder()
                {
                    Quality = (int)AppBuildSettings.Instance.CompressImgToolQualityLv
                };
                using (var outputStream = new FileStream(outputFileName, FileMode.Create))
                {
                    img.Save(outputStream, encoder);
                }

            }

            return true;
        }
        /// <summary>
        /// 使用pngquant壓縮png圖片
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <returns></returns>
        private static bool CompressPngOffline(string imgFileName, string outputFileName)
        {
            string pngquant = Path.Combine(Directory.GetParent(Application.dataPath).FullName, pngquantTool);

            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendFormat(" --force --quality {0}-{1}", (int)AppBuildSettings.Instance.CompressImgToolQualityMinLv, (int)AppBuildSettings.Instance.CompressImgToolQualityLv);
            strBuilder.AppendFormat(" --speed {0}", AppBuildSettings.Instance.CompressImgToolFastLv);
            strBuilder.AppendFormat(" --output \"{0}\"", outputFileName);
            strBuilder.AppendFormat(" -- \"{0}\"", imgFileName);

            var proceInfo = new System.Diagnostics.ProcessStartInfo(pngquant, strBuilder.ToString());
            proceInfo.CreateNoWindow = true;
            proceInfo.UseShellExecute = false;
            bool success;
            using (var proce = System.Diagnostics.Process.Start(proceInfo))
            {
                proce.WaitForExit();
                success = proce.ExitCode == 0;
                if (!success)
                {
                    Debug.LogWarningFormat("離線壓縮圖片:{0}失敗,ExitCode:{1}", imgFileName, proce.ExitCode);
                }
            }
            return success;
        }

3. 彈出Unity編輯器內(nèi)置資源選擇窗口:

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

?通過反射調(diào)用Unity編輯器內(nèi)置選文件窗口,需要注意反射調(diào)用不支持重載函數(shù),所以需要把參數(shù)填寫完整才能成功調(diào)用:

public class EditorUtilityExtension
{

    /// <summary>
    /// 選擇相對工程路徑文件夾
    /// </summary>
    /// <param name="title">標(biāo)題</param>
    /// <param name="relativePath">默認(rèn)打開的路徑(相對路徑)</param>
    /// <returns></returns>
    public static string OpenRelativeFolderPanel(string title, string relativePath)
    {
        var rootPath = Directory.GetParent(Application.dataPath).FullName;
        var curFullPath = Path.Combine(rootPath, relativePath);
        var selectPath = EditorUtility.OpenFolderPanel(title, curFullPath, curFullPath);

        return string.IsNullOrWhiteSpace(selectPath) ? selectPath : Path.GetRelativePath(rootPath, selectPath);
    }

    /// <summary>
    /// 打開UnityEditor內(nèi)置文件選擇界面
    /// </summary>
    /// <param name="assetTp"></param>
    /// <param name="searchFilter"></param>
    /// <param name="onObjectSelectorClosed"></param>
    /// <param name="objectSelectorID"></param>
    /// <returns></returns>
    public static bool OpenAssetSelector(Type assetTp, string searchFilter = null, Action<UnityEngine.Object> onObjectSelectorClosed = null, int objectSelectorID = 0)
    {
        var objSelector = Utility.Assembly.GetType("UnityEditor.ObjectSelector");
        var objSelectorInst = objSelector?.GetProperty("get", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)?.GetValue(objSelector);
        if (objSelectorInst == null) return false;

        var objSelectorInstTp = objSelectorInst.GetType();
        var showFunc = objSelectorInstTp.GetMethod("Show", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new System.Type[] { typeof(UnityEngine.Object), typeof(Type), typeof(UnityEngine.Object), typeof(bool), typeof(List<int>), typeof(Action<UnityEngine.Object>), typeof(Action<UnityEngine.Object>) }, null);
        if (showFunc == null) return false;

        showFunc.Invoke(objSelectorInst, new object[] { null, assetTp, null, false, null, onObjectSelectorClosed, null });
        if (!string.IsNullOrEmpty(searchFilter))
        {
            objSelectorInstTp.GetProperty("searchFilter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(objSelectorInst, searchFilter);
        }

        objSelectorInstTp.GetField("objectSelectorID", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(objSelectorInst, objectSelectorID);

        return true;
    }
}

4. 拖拽批量添加功能:

private void DrawDropArea()
    {
        var dragRect = EditorGUILayout.BeginVertical("box");
        {
            GUILayout.FlexibleSpace();
            EditorGUILayout.LabelField(dragAreaContent, centerLabelStyle);
            if (dragRect.Contains(Event.current.mousePosition))
            {
                if (Event.current.type == EventType.DragUpdated)
                {
                    DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
                }
                else if (Event.current.type == EventType.DragExited)
                {
                    if (DragAndDrop.objectReferences != null && DragAndDrop.objectReferences.Length > 0)
                    {
                        OnItemsDrop(DragAndDrop.objectReferences);
                    }

                }
            }
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndVertical();
        }
    }

/// <summary>
    /// 拖拽松手
    /// </summary>
    /// <param name="objectReferences"></param>
    /// <exception cref="NotImplementedException"></exception>
    private void OnItemsDrop(UnityEngine.Object[] objectReferences)
    {
        foreach (var item in objectReferences)
        {
            if (CheckItemType(item) == ItemType.NoSupport)
            {
                Debug.LogWarningFormat("添加失敗! 不支持的文件格式:{0}", AssetDatabase.GetAssetPath(item));
                continue;
            }
            AddItem(item);
        }
    }

模式二:Unity內(nèi)置壓縮批處理

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

?1. 通過編輯器腳本批量修改圖片TextureImporter屬性:

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

?通過下面代碼可以獲取上圖紅色區(qū)域的設(shè)置參數(shù):

var texSetting = new TextureImporterSettings();
texImporter.ReadTextureSettings(texSetting);

?通過下面代碼可以獲取針對各個(gè)平臺(tái)的設(shè)置參數(shù):

var texImporter = AssetImporter.GetAtPath(assetName) as TextureImporter;
var texPlatformSetting = texImporter.GetPlatformTextureSettings(EditorUserBuildSettings.activeBuildTarget.ToString());

?需要注意的是,不同平臺(tái)支持的圖片壓縮方式(Format)不同,可以通過反射調(diào)用Unity內(nèi)置API獲取對應(yīng)平臺(tái)支持的所有Format類型以供下拉選擇:

var getOptionsFunc = Utility.Assembly.GetType("UnityEditor.TextureImportValidFormats").GetMethod("GetPlatformTextureFormatValuesAndStrings", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
var paramsObjs = new object[] { TextureImporterType.Sprite, EditorUserBuildSettings.activeBuildTarget, null, null };
getOptionsFunc.Invoke(null, paramsObjs);

var formatValues = paramsObjs[2] as int[];
var formatDisplayOptions = paramsObjs[3] as string[];


...
//Format
        EditorGUILayout.BeginHorizontal();
        {
            overrideFormat = EditorGUILayout.ToggleLeft("Format", overrideFormat, GUILayout.Width(150));
            EditorGUI.BeginDisabledGroup(!overrideFormat);
            {
                compressPlatformSettings.format = (TextureImporterFormat)EditorGUILayout.IntPopup((int)compressPlatformSettings.format, formatDisplayOptions, formatValues);
                EditorGUI.EndDisabledGroup();
            }
            EditorGUILayout.EndHorizontal();
        }

2. 通過EditorUtility.FormatBytes(UnityEditor.TextureUtil.GetStorageMemorySizeLong(texture))方法可以獲取到對應(yīng)壓縮格式的文件占用大小,這樣就可以通過自動(dòng)比對篩選出最合適的壓縮格式。此方法不是公開方法,需要通過反射調(diào)用。

3. 編輯器代碼判斷貼圖是否符合壓縮格式要求

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮?

比如ETC2要求圖片像素寬高必須是4的倍數(shù),Crunch格式要求圖片寬高必須為POT(即2的N次方),對于不支持的壓縮的貼圖Unity還給了貼心警告,壓縮失敗時(shí)壓縮格式會(huì)回滾到默認(rèn)的通用格式,會(huì)造成貼圖大小不降反升。所以需要判斷貼圖是否壓縮成功,如果失敗了就設(shè)置一個(gè)相對通用的壓縮格式。

遺憾的是在Unity開源代碼中并沒有找到直接獲取是否壓縮成功的方法,但是可以通過判斷是否有警告字符以判斷是否壓縮成功:

/// <summary>
        /// 檢測貼圖是否適用壓縮格式
        /// </summary>
        /// <param name="texImporter"></param>
        /// <param name="warning"></param>
        /// <returns></returns>
        bool CheckTexFormatValid(TextureImporter texImporter, out string warning)
        {
            var impWarningFunc = texImporter.GetType().GetMethod("GetImportWarnings", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            warning = impWarningFunc.Invoke(texImporter, null) as string;
            return string.IsNullOrWhiteSpace(warning);
        }

模式三:創(chuàng)建圖集,圖集變體

?功能需求:

1. 根據(jù)用戶選定的文件夾,支持以文件夾或文件夾及其子文件夾為單位批量創(chuàng)建圖集(每個(gè)文件夾生成一個(gè)圖集文件),并且支持忽略把像素寬/高大于限制大小的圖片打進(jìn)圖集。

2. 創(chuàng)建AtlasVariant,AtlasVariant是用來按比例縮放SpriteAtlas的,用于資源大小優(yōu)化。勾選AtlasVariant后,生成圖集同時(shí)生成AtlasVariant。

3. 其他圖集設(shè)置參數(shù),同圖集的Inspector設(shè)置面板。

需要注意的是SpriteAtlas目前有v1和v2兩個(gè)版本,圖集格式分別為spriteatlas和spriteatlasv2:

【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮

?兩個(gè)版本的圖集創(chuàng)建方法不同, v1是SpriteAtlas,v2是SpriteAtlasAsset,可通過EditorSettings.spritePackerMode獲取當(dāng)前使用的圖集版本。

使用編輯器代碼創(chuàng)建圖集(SpriteAtlas),支持v1和v2:

/// <summary>
        /// 創(chuàng)建圖集
        /// </summary>
        /// <param name="atlasFilePath"></param>
        /// <param name="settings"></param>
        /// <param name="objectsForPack"></param>
        /// <param name="createAtlasVariant"></param>
        /// <param name="atlasVariantScale"></param>
        /// <returns></returns>
        public static SpriteAtlas CreateAtlas(string atlasName, AtlasSettings settings, UnityEngine.Object[] objectsForPack, bool createAtlasVariant = false, float atlasVariantScale = 1f)
        {
            CreateEmptySpriteAtlas(atlasName);
            SpriteAtlas result;
            if (EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2)
            {
                var atlas = SpriteAtlasAsset.Load(atlasName);
                atlas.SetIncludeInBuild(settings.includeInBuild ?? true);
                atlas.Add(objectsForPack);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                SpriteAtlasAsset.Save(atlas, atlasName);

                result = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasName);
            }
            else
            {
                var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasName);
                atlas.SetIncludeInBuild(settings.includeInBuild ?? true);
                atlas.Add(objectsForPack);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                result = atlas;
                AssetDatabase.SaveAssets();
            }

            if (createAtlasVariant)
            {
                var atlasVarSets = new AtlasVariantSettings()
                {
                    variantScale = atlasVariantScale,
                    readWrite = settings.readWrite,
                    mipMaps = settings.mipMaps,
                    sRGB = settings.sRGB,
                    filterMode = settings.filterMode,
                    texFormat = settings.texFormat,
                    compressQuality = settings.compressQuality
                };
                CreateAtlasVariant(result, atlasVarSets);
            }
            return result;
        }

使用編輯器代碼為指定圖集創(chuàng)建圖集變體:

/// <summary>
        /// 根據(jù)圖集對象生成圖集變體
        /// </summary>
        /// <param name="atlas"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static SpriteAtlas CreateAtlasVariant(SpriteAtlas atlasMaster, AtlasVariantSettings settings)
        {
            if (atlasMaster == null || atlasMaster.isVariant) return atlasMaster;
            var atlasFileName = AssetDatabase.GetAssetPath(atlasMaster);
            if (string.IsNullOrEmpty(atlasFileName))
            {
                Debug.LogError($"atlas '{atlasMaster.name}' is not a asset file.");
                return null;
            }

            var atlasVariantName = UtilityBuiltin.ResPath.GetCombinePath(Path.GetDirectoryName(atlasFileName), $"{Path.GetFileNameWithoutExtension(atlasFileName)}_Variant{Path.GetExtension(atlasFileName)}");

            SpriteAtlas varAtlas;
            if (EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2)
            {
                var atlas = SpriteAtlasAsset.Load(atlasFileName);
                atlas.SetIncludeInBuild(false);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                SpriteAtlasAsset.Save(atlas, atlasFileName);

                CreateEmptySpriteAtlas(atlasVariantName);
                var tmpVarAtlas = SpriteAtlasAsset.Load(atlasVariantName);
                tmpVarAtlas.SetIncludeInBuild(true);
                tmpVarAtlas.SetIsVariant(true);
                packSettings = tmpVarAtlas.GetPackingSettings();
                texSettings = tmpVarAtlas.GetTextureSettings();
                platformSettings = tmpVarAtlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                tmpVarAtlas.SetPackingSettings(packSettings);
                tmpVarAtlas.SetTextureSettings(texSettings);
                tmpVarAtlas.SetPlatformSettings(platformSettings);
                tmpVarAtlas.SetMasterAtlas(atlasMaster);
                tmpVarAtlas.SetVariantScale(settings.variantScale);
                SpriteAtlasAsset.Save(tmpVarAtlas, atlasVariantName);

                varAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasVariantName);
            }
            else
            {
                var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasFileName);
                atlas.SetIncludeInBuild(false);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);

                CreateEmptySpriteAtlas(atlasVariantName);
                var tmpVarAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasVariantName);
                tmpVarAtlas.SetIncludeInBuild(true);
                tmpVarAtlas.SetIsVariant(true);
                packSettings = tmpVarAtlas.GetPackingSettings();
                texSettings = tmpVarAtlas.GetTextureSettings();
                platformSettings = tmpVarAtlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                tmpVarAtlas.SetPackingSettings(packSettings);
                tmpVarAtlas.SetTextureSettings(texSettings);
                tmpVarAtlas.SetPlatformSettings(platformSettings);
                tmpVarAtlas.SetMasterAtlas(atlasMaster);
                tmpVarAtlas.SetVariantScale(settings.variantScale);
                AssetDatabase.SaveAssets();

                varAtlas = tmpVarAtlas;
            }

            return varAtlas;
        }

模式四:Animation Clip動(dòng)畫文件大小優(yōu)化

原理非常簡單,動(dòng)畫文件的位置、旋轉(zhuǎn)、縮放等數(shù)據(jù)以浮點(diǎn)型保存在動(dòng)畫文件,默認(rèn)精度太高,保留了一大串小數(shù)點(diǎn)后的數(shù)字,實(shí)際上不需要精度過大,保留3位小數(shù)即可。降低浮點(diǎn)型精度可以降低動(dòng)畫文件大小以減少打包后包體大小。

我這里直接偷懶使用正則匹配動(dòng)畫文件里的小數(shù)并降低小數(shù)的精度(注意,此方式只適用于Asset Serialization位Force Text模式,不支持Force Binary,Unity工程默認(rèn)是Force Text模式):

public static void OptimizeAnimationClips(List<string> list, int precision)
        {
            string pattern = $"(\\d+\\.[\\d]{{{precision},}})";

            int totalCount = list.Count;
            int finishCount = 0;
            foreach (var itmName in list)
            {
                if (File.GetAttributes(itmName) != FileAttributes.ReadOnly)
                {
                    if (Path.GetExtension(itmName).ToLower().CompareTo(".anim") == 0)
                    {
                        finishCount++;
                        if (EditorUtility.DisplayCancelableProgressBar(string.Format("壓縮浮點(diǎn)精度({0}/{1})", finishCount, totalCount), itmName, finishCount / (float)totalCount))
                        {
                            break;
                        }
                        var allTxt = File.ReadAllText(itmName);
                        // 將匹配到的浮點(diǎn)型數(shù)字替換為精確到3位小數(shù)的浮點(diǎn)型數(shù)字
                        string outputString = Regex.Replace(allTxt, pattern, match =>
                        float.Parse(match.Value).ToString($"F{precision}"));
                        File.WriteAllText(itmName, outputString);
                        Debug.LogFormat("----->壓縮動(dòng)畫浮點(diǎn)精度:{0}", itmName);
                    }
                }
            }
            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
        }

?工具的功能代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-409666.html

using UnityEditor.U2D;
using UnityEditor;
using UnityEngine;
using UnityEngine.U2D;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using TinifyAPI;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp;
using GameFramework;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace UGF.EditorTools
{
    public class AtlasSettings : IReference
    {
        public bool? includeInBuild = null;
        public bool? allowRotation = null;
        public bool? tightPacking = null;
        public bool? alphaDilation = null;
        public int? padding = null;
        public bool? readWrite = null;
        public bool? mipMaps = null;
        public bool? sRGB = null;
        public FilterMode? filterMode = null;
        public int? maxTexSize = null;
        public TextureImporterFormat? texFormat = null;
        public int? compressQuality = null;
        public virtual void Clear()
        {
            includeInBuild = null;
            allowRotation = null;
            tightPacking = null;
            alphaDilation = null;
            padding = null;
            readWrite = null;
            mipMaps = null;
            sRGB = null;
            filterMode = null;
            maxTexSize = null;
            texFormat = null;
            compressQuality = null;
        }
    }
    public class AtlasVariantSettings : AtlasSettings
    {
        public float variantScale = 0.5f;
        public override void Clear()
        {
            base.Clear();
            variantScale = 0.5f;
        }
        public static AtlasVariantSettings CreateFrom(AtlasSettings atlasSettings, float scale = 1f)
        {
            var settings = ReferencePool.Acquire<AtlasVariantSettings>();
            settings.includeInBuild = atlasSettings.includeInBuild;
            settings.allowRotation = atlasSettings.allowRotation;
            settings.tightPacking = atlasSettings.tightPacking;
            settings.alphaDilation = atlasSettings.alphaDilation;
            settings.padding = atlasSettings.padding;
            settings.readWrite = atlasSettings.readWrite;
            settings.mipMaps = atlasSettings.mipMaps;
            settings.sRGB = atlasSettings.sRGB;
            settings.filterMode = atlasSettings.filterMode;
            settings.maxTexSize = atlasSettings.maxTexSize;
            settings.texFormat = atlasSettings.texFormat;
            settings.compressQuality = atlasSettings.compressQuality;
            settings.variantScale = scale;
            return settings;
        }
    }
    public class CompressTool
    {
#if UNITY_EDITOR_WIN
        const string pngquantTool = "Tools/CompressImageTools/pngquant_win/pngquant.exe";
#elif UNITY_EDITOR_OSX
        const string pngquantTool = "Tools/CompressImageTools/pngquant_mac/pngquant";
#endif
        /// <summary>
        /// 使用TinyPng在線壓縮,支持png,jpg,webp
        /// </summary>
        public static async Task<bool> CompressOnlineAsync(string imgFileName, string outputFileName, string tinypngKey)
        {
            if (string.IsNullOrWhiteSpace(tinypngKey))
            {
                return false;
            }
            Tinify.Key = tinypngKey;
            var srcImg = TinifyAPI.Tinify.FromFile(imgFileName);
            await srcImg.ToFile(outputFileName);
            return srcImg.IsCompletedSuccessfully;
        }

        /// <summary>
        /// 使用pngquant離線壓縮,只支持png
        /// </summary>
        public static bool CompressImageOffline(string imgFileName, string outputFileName)
        {
            var fileExt = Path.GetExtension(imgFileName).ToLower();
            switch (fileExt)
            {
                case ".png":
                    return CompressPngOffline(imgFileName, outputFileName);
                case ".jpg":
                    return CompressJpgOffline(imgFileName, outputFileName);
            }
            return false;
        }
        /// <summary>
        /// 按比例縮放圖片尺寸
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        public static bool ResizeImage(string imgFileName, string outputFileName, float scale)
        {
            using (var img = SixLabors.ImageSharp.Image.Load(imgFileName))
            {
                int scaleWidth = (int)(img.Width * scale);
                int scaleHeight = (int)(img.Height * scale);
                img.Mutate(x => x.Resize(scaleWidth, scaleHeight));
                img.Save(outputFileName);
            }
            return true;
        }
        /// <summary>
        /// 設(shè)置圖片尺寸
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static bool ResizeImage(string imgFileName, string outputFileName, int width, int height)
        {
            using (var img = SixLabors.ImageSharp.Image.Load(imgFileName))
            {
                img.Mutate(x => x.Resize(width, height));
                img.Save(outputFileName);
            }
            return true;
        }
        /// <summary>
        /// 使用ImageSharp壓縮jpg圖片
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <returns></returns>
        private static bool CompressJpgOffline(string imgFileName, string outputFileName)
        {
            using (var img = SixLabors.ImageSharp.Image.Load(imgFileName))
            {
                var encoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder()
                {
                    Quality = (int)EditorToolSettings.Instance.CompressImgToolQualityLv
                };
                using (var outputStream = new FileStream(outputFileName, FileMode.Create))
                {
                    img.Save(outputStream, encoder);
                }

            }

            return true;
        }
        /// <summary>
        /// 使用pngquant壓縮png圖片
        /// </summary>
        /// <param name="imgFileName"></param>
        /// <param name="outputFileName"></param>
        /// <returns></returns>
        private static bool CompressPngOffline(string imgFileName, string outputFileName)
        {
            string pngquant = Path.Combine(Directory.GetParent(Application.dataPath).FullName, pngquantTool);

            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendFormat(" --force --quality {0}-{1}", (int)EditorToolSettings.Instance.CompressImgToolQualityMinLv, (int)EditorToolSettings.Instance.CompressImgToolQualityLv);
            strBuilder.AppendFormat(" --speed {0}", EditorToolSettings.Instance.CompressImgToolFastLv);
            strBuilder.AppendFormat(" --output \"{0}\"", outputFileName);
            strBuilder.AppendFormat(" -- \"{0}\"", imgFileName);

            var proceInfo = new System.Diagnostics.ProcessStartInfo(pngquant, strBuilder.ToString());
            proceInfo.CreateNoWindow = true;
            proceInfo.UseShellExecute = false;
            bool success;
            using (var proce = System.Diagnostics.Process.Start(proceInfo))
            {
                proce.WaitForExit();
                success = proce.ExitCode == 0;
                if (!success)
                {
                    Debug.LogWarningFormat("離線壓縮圖片:{0}失敗,ExitCode:{1}", imgFileName, proce.ExitCode);
                }
            }
            return success;
        }
        /// <summary>
        /// 創(chuàng)建圖集
        /// </summary>
        /// <param name="atlasFilePath"></param>
        /// <param name="settings"></param>
        /// <param name="objectsForPack"></param>
        /// <param name="createAtlasVariant"></param>
        /// <param name="atlasVariantScale"></param>
        /// <returns></returns>
        public static SpriteAtlas CreateAtlas(string atlasName, AtlasSettings settings, UnityEngine.Object[] objectsForPack, bool createAtlasVariant = false, float atlasVariantScale = 1f)
        {
            CreateEmptySpriteAtlas(atlasName);
            SpriteAtlas result;
            if (EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2)
            {
                var atlas = SpriteAtlasAsset.Load(atlasName);
                atlas.SetIncludeInBuild(settings.includeInBuild ?? true);
                atlas.Add(objectsForPack);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                SpriteAtlasAsset.Save(atlas, atlasName);

                result = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasName);
            }
            else
            {
                var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasName);
                atlas.SetIncludeInBuild(settings.includeInBuild ?? true);
                atlas.Add(objectsForPack);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                result = atlas;
                AssetDatabase.SaveAssets();
            }

            if (createAtlasVariant)
            {
                var atlasVarSets = new AtlasVariantSettings()
                {
                    variantScale = atlasVariantScale,
                    readWrite = settings.readWrite,
                    mipMaps = settings.mipMaps,
                    sRGB = settings.sRGB,
                    filterMode = settings.filterMode,
                    texFormat = settings.texFormat,
                    compressQuality = settings.compressQuality
                };
                CreateAtlasVariant(result, atlasVarSets);
            }
            return result;
        }
        private static void ModifySpriteAtlasSettings(AtlasSettings input, ref SpriteAtlasPackingSettings packSets, ref SpriteAtlasTextureSettings texSets, ref TextureImporterPlatformSettings platSets)
        {
            packSets.enableRotation = input.allowRotation ?? packSets.enableRotation;
            packSets.enableTightPacking = input.tightPacking ?? packSets.enableTightPacking;
            packSets.enableAlphaDilation = input.alphaDilation ?? packSets.enableAlphaDilation;
            packSets.padding = input.padding ?? packSets.padding;
            texSets.readable = input.readWrite ?? texSets.readable;
            texSets.generateMipMaps = input.mipMaps ?? texSets.generateMipMaps;
            texSets.sRGB = input.sRGB ?? texSets.sRGB;
            texSets.filterMode = input.filterMode ?? texSets.filterMode;
            platSets.overridden = null != input.maxTexSize || null != input.texFormat || null != input.compressQuality;
            platSets.maxTextureSize = input.maxTexSize ?? platSets.maxTextureSize;
            platSets.format = input.texFormat ?? platSets.format;
            platSets.compressionQuality = input.compressQuality ?? platSets.compressionQuality;
        }
        /// <summary>
        /// 根據(jù)文件夾名字返回一個(gè)圖集名
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public static string GetAtlasExtensionV1V2()
        {
            return EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2 ? ".spriteatlasv2" : ".spriteatlas";
        }
        public static void CreateEmptySpriteAtlas(string atlasAssetName)
        {
            if (EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2)
            {
                SpriteAtlasAsset.Save(new SpriteAtlasAsset(), atlasAssetName);
            }
            else
            {
                AssetDatabase.CreateAsset(new SpriteAtlas(), atlasAssetName);
            }
            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
        }
        /// <summary>
        /// 根據(jù)圖集對象生成圖集變體
        /// </summary>
        /// <param name="atlas"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static SpriteAtlas CreateAtlasVariant(SpriteAtlas atlasMaster, AtlasVariantSettings settings)
        {
            if (atlasMaster == null || atlasMaster.isVariant) return atlasMaster;
            var atlasFileName = AssetDatabase.GetAssetPath(atlasMaster);
            if (string.IsNullOrEmpty(atlasFileName))
            {
                Debug.LogError($"atlas '{atlasMaster.name}' is not a asset file.");
                return null;
            }

            var atlasVariantName = UtilityBuiltin.ResPath.GetCombinePath(Path.GetDirectoryName(atlasFileName), $"{Path.GetFileNameWithoutExtension(atlasFileName)}_Variant{Path.GetExtension(atlasFileName)}");

            SpriteAtlas varAtlas;
            if (EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2)
            {
                var atlas = SpriteAtlasAsset.Load(atlasFileName);
                atlas.SetIncludeInBuild(false);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);
                SpriteAtlasAsset.Save(atlas, atlasFileName);

                CreateEmptySpriteAtlas(atlasVariantName);
                var tmpVarAtlas = SpriteAtlasAsset.Load(atlasVariantName);
                tmpVarAtlas.SetIncludeInBuild(true);
                tmpVarAtlas.SetIsVariant(true);
                packSettings = tmpVarAtlas.GetPackingSettings();
                texSettings = tmpVarAtlas.GetTextureSettings();
                platformSettings = tmpVarAtlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                tmpVarAtlas.SetPackingSettings(packSettings);
                tmpVarAtlas.SetTextureSettings(texSettings);
                tmpVarAtlas.SetPlatformSettings(platformSettings);
                tmpVarAtlas.SetMasterAtlas(atlasMaster);
                tmpVarAtlas.SetVariantScale(settings.variantScale);
                SpriteAtlasAsset.Save(tmpVarAtlas, atlasVariantName);

                varAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasVariantName);
            }
            else
            {
                var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasFileName);
                atlas.SetIncludeInBuild(false);
                var packSettings = atlas.GetPackingSettings();
                var texSettings = atlas.GetTextureSettings();
                var platformSettings = atlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                atlas.SetPackingSettings(packSettings);
                atlas.SetTextureSettings(texSettings);
                atlas.SetPlatformSettings(platformSettings);

                CreateEmptySpriteAtlas(atlasVariantName);
                var tmpVarAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasVariantName);
                tmpVarAtlas.SetIncludeInBuild(true);
                tmpVarAtlas.SetIsVariant(true);
                packSettings = tmpVarAtlas.GetPackingSettings();
                texSettings = tmpVarAtlas.GetTextureSettings();
                platformSettings = tmpVarAtlas.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString());
                ModifySpriteAtlasSettings(settings, ref packSettings, ref texSettings, ref platformSettings);
                tmpVarAtlas.SetPackingSettings(packSettings);
                tmpVarAtlas.SetTextureSettings(texSettings);
                tmpVarAtlas.SetPlatformSettings(platformSettings);
                tmpVarAtlas.SetMasterAtlas(atlasMaster);
                tmpVarAtlas.SetVariantScale(settings.variantScale);
                AssetDatabase.SaveAssets();

                varAtlas = tmpVarAtlas;
            }

            return varAtlas;
        }
        /// <summary>
        /// 根據(jù)Atlas文件名為Atlas生成Atlas變體(Atlas Variant)
        /// </summary>
        /// <param name="atlasFile"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static SpriteAtlas CreateAtlasVariant(string atlasFile, AtlasVariantSettings settings)
        {
            var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasFile);

            return CreateAtlasVariant(atlas, settings);
        }

        /// <summary>
        /// 批量重新打包圖集
        /// </summary>
        /// <param name="spriteAtlas"></param>
        public static void PackAtlases(SpriteAtlas[] spriteAtlas)
        {
            SpriteAtlasUtility.PackAtlases(spriteAtlas, EditorUserBuildSettings.activeBuildTarget);
        }

        public static void OptimizeAnimationClips(List<string> list, int precision)
        {
            string pattern = $"(\\d+\\.[\\d]{{{precision},}})";

            int totalCount = list.Count;
            int finishCount = 0;
            foreach (var itmName in list)
            {
                if (File.GetAttributes(itmName) != FileAttributes.ReadOnly)
                {
                    if (Path.GetExtension(itmName).ToLower().CompareTo(".anim") == 0)
                    {
                        finishCount++;
                        if (EditorUtility.DisplayCancelableProgressBar(string.Format("壓縮浮點(diǎn)精度({0}/{1})", finishCount, totalCount), itmName, finishCount / (float)totalCount))
                        {
                            break;
                        }
                        var allTxt = File.ReadAllText(itmName);
                        // 將匹配到的浮點(diǎn)型數(shù)字替換為精確到3位小數(shù)的浮點(diǎn)型數(shù)字
                        string outputString = Regex.Replace(allTxt, pattern, match =>
                        float.Parse(match.Value).ToString($"F{precision}"));
                        File.WriteAllText(itmName, outputString);
                        Debug.LogFormat("----->壓縮動(dòng)畫浮點(diǎn)精度:{0}", itmName);
                    }
                }
            }
            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
        }
    }
}

到了這里,關(guān)于【Unity編輯器擴(kuò)展】包體優(yōu)化神器,圖片壓縮,批量生成圖集/圖集變體,動(dòng)畫壓縮的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Unity編輯器擴(kuò)展(外掛)

    Unity編輯器擴(kuò)展(外掛)

    每日一句:未來的樣子藏在現(xiàn)在的努力里 目錄 什么是編譯器開發(fā) C#特性[System.Serializable] 特殊目錄 命名空間 /*檢視器屬性控制*/ ?? ?//添加變量懸浮提示文字 ??? //給數(shù)值設(shè)定范圍(最小0,最大150) //指定輸入框,擁有5行 //默認(rèn)顯示5行,最多顯示10行內(nèi)容,再多用滾動(dòng)條控

    2024年01月24日
    瀏覽(25)
  • Unity編輯器擴(kuò)展之GenericMenu菜單擴(kuò)展

    Unity編輯器擴(kuò)展之GenericMenu菜單擴(kuò)展

    內(nèi)容將會(huì)持續(xù)更新,有錯(cuò)誤的地方歡迎指正,謝謝! ? Unity編輯器擴(kuò)展之GenericMenu自定義菜單 ? ? ? TechX 堅(jiān)持將創(chuàng)新的科技帶給世界! 擁有更好的學(xué)習(xí)體驗(yàn) —— 不斷努力,不斷進(jìn)步,不斷探索 TechX —— 心探索、心進(jìn)取! 助力快速掌握 GenericMenu 菜單擴(kuò)展 為初學(xué)者節(jié)省寶貴的

    2024年02月01日
    瀏覽(38)
  • 【Unity編輯器擴(kuò)展】| 頂部菜單欄擴(kuò)展 MenuItem
  • Unity 擴(kuò)展自定義編輯器窗口

    Unity 擴(kuò)展自定義編輯器窗口

    在Assets文件夾路徑下任意位置創(chuàng)建Editor文件夾,將擴(kuò)展編輯器的代碼放在Editor文件夾下 代碼中首先引用命名空間 然后將創(chuàng)建的類繼承自EditorWindow 然后通過擴(kuò)展編輯器菜單功能調(diào)用創(chuàng)建窗口的方法 要注意方法中泛型參數(shù)需要傳入的是自己代碼的類,這個(gè)功能是根據(jù)后面OnGUI方

    2024年04月27日
    瀏覽(19)
  • Unity 編輯器擴(kuò)展之 Attribute

    Unity 編輯器擴(kuò)展之 Attribute

    Unity內(nèi)置屬性[Attribute]是一種類似修飾功能的標(biāo)簽??梢詫nSceneGUI,InspectorGUI,MenuGUI,WindowGUI等實(shí)現(xiàn)各種各樣的GUI擴(kuò)展。用戶只要添加上特性標(biāo)簽,就能夠自由的使用這些擴(kuò)展功能。下面列出一些常用的標(biāo)簽: 隱藏屬性在Inspector面板上的顯示。在繼承了MonoBehaviour的類中,用

    2023年04月09日
    瀏覽(24)
  • Unity編輯擴(kuò)展:功能篇之Json數(shù)據(jù)編輯器

    Unity編輯擴(kuò)展:功能篇之Json數(shù)據(jù)編輯器

    前言 編輯器擴(kuò)展算是比較純粹的功能開發(fā),基本沒有什么理論知識(shí),都是一些 Unity 相關(guān)接口的使用與數(shù)據(jù)類型的設(shè)計(jì)操作等。在本篇文章主要的文字描述基本都是在做代碼解釋,為了使內(nèi)容接受度更高,我會(huì)盡量描述到代碼結(jié)構(gòu)中的每個(gè)細(xì)節(jié)。如果有對此不太了解又很感興

    2024年02月06日
    瀏覽(25)
  • 【Unity編輯器擴(kuò)展】| Inspector監(jiān)視器面板擴(kuò)展

    【Unity編輯器擴(kuò)展】| Inspector監(jiān)視器面板擴(kuò)展

    前言 前面我們介紹了Unity中編輯器擴(kuò)展的一些基本概念及基礎(chǔ)知識(shí),還有編輯器擴(kuò)展中用到的相關(guān)特性Attribute介紹。 后面就來針對Uniity編輯器擴(kuò)展中比較常用的模塊進(jìn)行學(xué)習(xí)介紹。 本文就來詳細(xì)介紹一下Unity編輯器擴(kuò)展中關(guān)于 Inspector面板 擴(kuò)展功能學(xué)習(xí)。

    2024年02月08日
    瀏覽(20)
  • 盤點(diǎn)Unity幾款編輯器擴(kuò)展工具

    盤點(diǎn)Unity幾款編輯器擴(kuò)展工具

    unity 編輯器一個(gè)不容忽視的強(qiáng)大之處就是非常易于自定義擴(kuò)展工具,來滿足各種各樣的美術(shù)、策劃及程序上的需求。今天為大家介紹Asset Store資源商店中幾款實(shí)用的編輯器擴(kuò)展工具,幫助大家直接在Unity編輯器中完成3D建模與調(diào)整工作,免去與其它軟件進(jìn)行數(shù)據(jù)轉(zhuǎn)換的過程,從

    2024年04月09日
    瀏覽(25)
  • 【Unity編輯器擴(kuò)展】| 自定義窗口和面板
  • Unity編輯器擴(kuò)展-第四集-獲取物體的方法

    Unity編輯器擴(kuò)展-第四集-獲取物體的方法

    第三集鏈接:Unity編輯器擴(kuò)展-第三集-添加按鈕到組件菜單并且重置組件_菌菌巧樂茲的博客-CSDN博客 ?一、本節(jié)目標(biāo)+效果展示 1.改選中單個(gè)物體的名字 2.改選中所有物體的名字 ?3.選中了所有的物體,但只改第一層物體的名稱 ?4.來個(gè)有用的(選中的所有物體,按順序起名)

    2024年02月14日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包