Unity —— 图集参数 & 自动图集生成

一. 图集参数

Atlas Settings(图集设置)

  1. 基础设置
参数 含义
Allow Rotation 允许打包时旋转 Sprite 以节省空间(UGUI 建议关闭,旋转可能导致 UI 异常)
Tight Packing 紧密打包,按像素轮廓打包(非矩形),更节省空间,但有一定性能开销
Alpha Dilation Alpha 扩展,向外扩展透明边缘颜色,减少图片边缘渗色问题
Padding 图集中每张图片之间的像素间距,防止图片边缘渗色(推荐值:2~4)
  • Allow Rotation 和 Tight Packing同时打开时, 会出现异常 => 如果在图集中图片被旋转了, 那么使用时, 也会被旋转

  1. Texture Settings(纹理设置)
参数 含义
Read/Write 开启后可通过脚本读写纹理像素,会占用额外内存
Generate Mip Maps 生成 Mip Maps,适用于 3D 场景,UI 通常不需要开启
sRGB 将纹理作为 sRGB 颜色空间处理(默认开启)
Filter Mode 纹理过滤模式:Point(像素风)/ Bilinear(双线性)/ Trilinear(三线性)
Aniso Level 各向异性过滤等级,提升斜视角纹理质量(0~16,UI 通常设为 1)
  • Read/Write: 相当于在内存中创建一个副本进行读写操作, 所以对于开启此选项的图片来说, 内存为未开启的两倍
  • Read/Write:与alphaHitTestMinimumThreshold参数相关联,开启后才能使用; 打图集后alphaHitTestMinimumThreshold参数失效
  • sRGB: 详情看伽马空间和线性空间的介绍
  • Generate Mip Maps
    • 远近关系Mip Map 通过根据物体与摄像机的距离选择合适分辨率的纹理,来减少远处物体的过度渲染,从而提高渲染性能
    • Project Setting 中的Quality 里面的 Global MipMap Limit,用于控制全局范围内的 Mip Map 使用级别
    • 限制最高级别的纹理细节:通过设置一个特定的限制值,开发者可以指定游戏只能使用到某个级别的 Mip Map。例如,限制在较低级别可能导致纹理更加模糊,但提高运行效率

  1. Format Settings(平台压缩格式)
参数 含义
Max Texture Size 图集最大尺寸
Format 纹理压缩格式,如 RGBA32ETC2ASTCDXT5
Compression 压缩质量:None / Low Quality / Normal Quality / High Quality
Use Crunch Compression 使用 Crunch 压缩,进一步压缩体积(会增加解压时间)
Compressor Quality Crunch 压缩质量(0~100)
  • Max Texture Size: 即一张图的尺寸, 尺寸越大,可以容纳的图片越多
  • Format是压缩格式, 而Compression是在该压缩格式下的压缩程度

  1. 常用压缩格式
格式 平台 说明
RGBA32 通用 无压缩,质量最高,体积最大
DXT5 PC/Windows 支持透明,压缩比高
ETC2 Android 支持透明通道,Android 推荐
ASTC iOS/Android 灵活压缩比,现代移动端推荐
PVRTC iOS 旧版 iOS 格式,需尺寸为 2 的幂次方

二. 图集生成代码

csharp 复制代码
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine.U2D;
using UnityEngine;
using System.Reflection;

namespace LogicEditor.Editor
{
    /// <summary>
    /// 自动图集生成器
    /// 用于自动扫描指定文件夹下的图片资源,并生成对应的Sprite Atlas(精灵图集)
    /// 支持多平台压缩格式设置,并验证图集页数不超过限制
    /// </summary>
    public static class AutoAtlasGenerator
    {
        // 支持的图片文件扩展名
        private static readonly string[] SupportedImageExtensions = { ".png", ".jpg" };

        /// <summary>
        /// 获取图集打包后的实际页数
        /// 使用Unity内部API获取图集预览纹理,从而得到真实的页数
        /// </summary>
        /// <param name="atlas">要检查的图集对象</param>
        /// <param name="atlasPath">图集文件路径</param>
        /// <returns>图集页数,无法获取时返回1</returns>
        private static int GetPackedPageCount(SpriteAtlas atlas, string atlasPath)
        {
            // 通过反射获取Unity内部API:SpriteAtlasExtensions.GetPreviewTextures
            // 此方法可以获取图集打包后的实际纹理页
            var editorAsm = typeof(SpriteAtlasUtility).Assembly;
            var extType = editorAsm.GetType("UnityEditor.U2D.SpriteAtlasExtensions");
            if (extType != null)
            {
                var mi = extType.GetMethod("GetPreviewTextures", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(SpriteAtlas) }, null);
                if (mi != null)
                {
                    var textures = mi.Invoke(null, new object[] { atlas }) as Texture2D[];
                    if (textures != null)
                        return textures.Length;
                }
            }

            return 1;
        }

        /// <summary>
        /// 处理单个文件夹,为其生成或更新图集
        /// </summary>
        /// <param name="folderPath">要处理的文件夹路径</param>
        /// <param name="outputPath">图集输出路径</param>
        private static void ProcessSingleFolder(string folderPath, string outputPath)
        {
            // 获取文件夹下所有图片文件(单个文件夹进行读取)
            string[] imagePaths = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly);
            List<Object> validTextures = new List<Object>();

            // 筛选有效的图片资源
            foreach (var path in imagePaths)
            {
                bool isValidImage = false;
                foreach (var ext in SupportedImageExtensions)
                {
                    if (path.EndsWith(ext))
                    {
                        isValidImage = true;
                        break;
                    }
                }

                if (isValidImage)
                {
                    string assetPath = path.Replace(Application.dataPath, "Assets");
                    Object tex = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);
                    if (tex != null)
                        validTextures.Add(tex);
                }
            }

            // 如果文件夹中没有有效图片,跳过处理
            if (validTextures.Count == 0)
                return;

            // 创建或加载图集
            string folderName = new DirectoryInfo(folderPath).Name;
            string atlasPath = Path.Combine(outputPath, folderName + ".spriteatlas").Replace("\\", "/");
            // 先加载图集, 如果有的话
            SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath);

            if (atlas == null)
            {
                atlas = new SpriteAtlas();
                SetAtlasSettings(atlas);
                AssetDatabase.CreateAsset(atlas, atlasPath);
            }

            // 清空图集并添加新的图片资源
            atlas.Remove(atlas.GetPackables());
            atlas.Add(validTextures.ToArray());
            
            // 打包图集
            SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] { atlas }, EditorUserBuildSettings.activeBuildTarget, false);
            AssetDatabase.SaveAssets();

            // 验证图集页数
            int pageCount = GetPackedPageCount(atlas, atlasPath);
            if (pageCount > 1)
            {
                throw new System.Exception($"图集【{folderPath}】页数为 {pageCount},超出限制,路径:{atlasPath}");
            }
            else
            {
                Debug.Log($"图集【{folderPath}】页数为 {pageCount},正常");
            }
        }

        /// <summary>
        /// 配置图集的打包设置和平台压缩格式
        /// 包括打包参数、纹理设置以及各平台的压缩格式配置
        /// </summary>
        /// <param name="atlas">要配置的图集对象</param>
        public static void SetAtlasSettings(SpriteAtlas atlas)
        {
            // 打包设置
            atlas.SetPackingSettings(new SpriteAtlasPackingSettings
            {
                padding = 4,
                enableRotation = true,
                enableTightPacking = false,
                enableAlphaDilation = false,
            });

            // 纹理设置
            atlas.SetTextureSettings(new SpriteAtlasTextureSettings
            {
                sRGB = true,
                readable = false,
                generateMipMaps = false,
                filterMode = FilterMode.Bilinear
            });

            // 默认平台设置
            atlas.SetPlatformSettings(new TextureImporterPlatformSettings
            {
                name = "DefaultTexturePlatform",
                overridden = false,
                maxTextureSize = 2048
            });

            // iOS平台设置:使用ASTC 4x4压缩
            atlas.SetPlatformSettings(new TextureImporterPlatformSettings
            {
                name = "iPhone",
                overridden = true,
                format = TextureImporterFormat.ASTC_4x4,
                compressionQuality = (int)TextureCompressionQuality.Best
            });

            // Android平台设置:使用ASTC 4x4压缩
            atlas.SetPlatformSettings(new TextureImporterPlatformSettings
            {
                name = "Android",
                overridden = true,
                format = TextureImporterFormat.ASTC_4x4,
                compressionQuality = (int)TextureCompressionQuality.Best,
                androidETC2FallbackOverride = AndroidETC2FallbackOverride.UseBuildSettings
            });
        }

        /// <summary>
        /// 生成指定路径下的所有图集
        /// 扫描源文件夹及其所有子目录,为每个目录生成对应的图集文件
        /// </summary>
        /// <param name="sourceFolder">源图片文件夹路径</param>
        /// <param name="outputFolder">图集输出文件夹路径</param>
        public static void GenerateAtlases(string sourceFolder, string outputFolder)
        {
            // 验证路径是否存在
            if (!Directory.Exists(sourceFolder))
            {
                throw new System.Exception($"源图片文件夹不存在: {sourceFolder}");
            }

            if (!Directory.Exists(outputFolder))
            {
                throw new System.Exception($"输出文件夹不存在: {outputFolder}");
            }

            // 获取所有子目录(包括根目录)
            List<string> allDirs = new List<string>();
            allDirs.Add(sourceFolder);
            allDirs.AddRange(Directory.GetDirectories(sourceFolder, "*", SearchOption.AllDirectories));

            // 处理每个目录
            foreach (string dir in allDirs)
            {
                // 跳过包含"_NoNeedAtlas"的目录
                if (new DirectoryInfo(dir).Name.Contains("_NoNeedAtlas"))
                {
                    Debug.Log($"忽略目录: {dir}");
                    continue;
                }

                ProcessSingleFolder(dir, outputFolder);
            }

            // 刷新资源数据库
            AssetDatabase.Refresh();
            Debug.Log($"图集生成完成!");
        }
    }
}
相关推荐
SmalBox1 天前
【节点】[GatherTexture2DNode节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox2 天前
【节点】[CubemapAsset节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox3 天前
【节点】[CalculateLevelOfDetailTexture2DNode节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox4 天前
【节点】[Screen节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox5 天前
【节点】[SceneDepthDifference节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox6 天前
【节点】[SceneDepth节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox7 天前
【节点】[SceneColor节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox8 天前
【节点】[Object节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox9 天前
【节点】[Fog节点]原理解析与实际应用
unity3d·游戏开发·图形学