UGUI 之 SpritePacker打包参数(四)

发表于2015-07-20
评论0 2.1k浏览
上篇文章说了UGUI上图集的使用,这一篇继续看看SpritePacker怎么打包图集。我觉得我们有必要对比一下NGUI的图集,NGUI在打包图集的时候图集的默认格式是RGBA32,也就是支持带透明通道的图片,这样一张1024的图集也就是4M内存。为了优化图集,我们可以选择把带透明通道图片 和 不带透明通道的图片分开打图集,这样可以减少内存的占用量。

然而着一切的一切在NGUI上都需要手动操作,而SpritePacker则全自动完成。Sprite上的Packing Tag 同一标识的图片UGUI会把相同图片格式的图片打包成同一图集。如下图所示,MomoAtals和RUORUOAtlas就是Packing Tag的标识符,那么此时根据这两个标识符SpritePacker将打出两个图集出来。 因为MomoAtlas这些图片中,一部分是RGBA32格式,还有一部分是ETC 4bits格式,那么MomoAtlas将被在分成两个图集,就是尾缀带Group的。



打包Sprite Packer有两个打包模式,如下图所示分别是DefaultPackerPolicy和TightPackerPolicy。



DefaultPackerPolicy:是默认的打包方式,也是矩形打包方式。他会把所有的小图按照矩形的方式来排列,如果宽高不一样的图片,它们会自动补起。

TightPackerPolicy:是紧密打包方式,也就是尽可能的把图片都打包在图集上,这种方式要比DefaultPackerPolicy打包的图片更多一些,也就是更省空间。



根据图集的布局可以清晰的看到TightPackerPolicy图集更加紧密。



DefaultPackerPolicy模式打包是unity所推荐的,理论上所有图集都可以使用DefaultPackerPolicy来完成打包。还有一个特性就是可以让图集中某几张图片单独采取DefaultPackerPolicy或者TightPackerPolicy的方式。

如下图所示,比如当前打包图集是DefaultPackerPolicy 那么小图中[TIGHT]开头的就表示单独这张图采用TightPackerPolicy打包模式。



如下图所示,比如当前打包图集是TightPackerPolicy 那么小图中[RECT]开头的就表示单独这张图采用DefaultPackerPolicy打包模式。



Unity只提供了这两种图集打包方法。假如我想自定义打包方式咋办?比如我想设置图片打包格式,或者图集大小等等怎么办?把如下代码放在Editor文件夹下, 在代码里面就可以设置图集的属性了。

[C#] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEditor.Sprites;
using System.Collections.Generic;
 
// DefaultPackerPolicy will pack rectangles no matter what Sprite mesh type is unless their packing tag contains "[TIGHT]".
class DefaultPackerPolicySample : UnityEditor.Sprites.IPackerPolicy
{
        protected class Entry
        {
                public Sprite            sprite;
                public AtlasSettings     settings;
                public string            atlasName;
                public SpritePackingMode packingMode;
        }
         
        public virtual int GetVersion() { return 1; }
         
        protected virtual string TagPrefix { get { return "[TIGHT]"; } }
        protected virtual bool AllowTightWhenTagged { get { return true; } }
         
        public void OnGroupAtlases(BuildTarget target, PackerJob job, int[] textureImporterInstanceIDs)
        {
                List<Entry> entries = new List<Entry>();
                 
                foreach (int instanceID in textureImporterInstanceIDs)
                {
                        TextureImporter ti = EditorUtility.InstanceIDToObject(instanceID) as TextureImporter;
                         
                        TextureImportInstructions ins = new TextureImportInstructions();
                        ti.ReadTextureImportInstructions(ins, target);
                         
                        TextureImporterSettings tis = new TextureImporterSettings();
                        ti.ReadTextureSettings(tis);
                         
                        Sprite[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(ti.assetPath).Select(x => x as Sprite).Where(x => x != null).ToArray();
                        foreach (Sprite sprite in sprites)
                        {
                                //在这里设置每个图集的参数
                                Entry entry = new Entry();
                                entry.sprite = sprite;
                                entry.settings.format = ins.desiredFormat;
                                entry.settings.usageMode = ins.usageMode;
                                entry.settings.colorSpace = ins.colorSpace;
                                entry.settings.compressionQuality = ins.compressionQuality;
                                entry.settings.filterMode = Enum.IsDefined(typeof(FilterMode), ti.filterMode) ? ti.filterMode : FilterMode.Bilinear;
                                entry.settings.maxWidth = 1024;
                                entry.settings.maxHeight = 1024;
                                entry.atlasName = ParseAtlasName(ti.spritePackingTag);
                                entry.packingMode = GetPackingMode(ti.spritePackingTag, tis.spriteMeshType);
                                 
                                entries.Add(entry);
                        }
                         
                        Resources.UnloadAsset(ti);
                }
                 
                // First split sprites into groups based on atlas name
                var atlasGroups =
                        from e in entries
                                group e by e.atlasName;
                foreach (var atlasGroup in atlasGroups)
                {
                        int page = 0;
                        // Then split those groups into smaller groups based on texture settings
                        var settingsGroups =
                                from t in atlasGroup
                                        group t by t.settings;
                        foreach (var settingsGroup in settingsGroups)
                        {
                                string atlasName = atlasGroup.Key;
                                if (settingsGroups.Count() > 1)
                                        atlasName += string.Format(" (Group {0})", page);
                                 
                                job.AddAtlas(atlasName, settingsGroup.Key);
                                foreach (Entry entry in settingsGroup)
                                {
                                        job.AssignToAtlas(atlasName, entry.sprite, entry.packingMode, SpritePackingRotation.None);
                                }
                                 
                                ++page;
                        }
                }
        }
         
        protected bool IsTagPrefixed(string packingTag)
        {
                packingTag = packingTag.Trim();
                if (packingTag.Length < TagPrefix.Length)
                        return false;
                return (packingTag.Substring(0, TagPrefix.Length) == TagPrefix);
        }
         
        private string ParseAtlasName(string packingTag)
        {
                string name = packingTag.Trim();
                if (IsTagPrefixed(name))
                        name = name.Substring(TagPrefix.Length).Trim();
                return (name.Length == 0) ? "(unnamed)" : name;
        }
         
        private SpritePackingMode GetPackingMode(string packingTag, SpriteMeshType meshType)
        {
                if (meshType == SpriteMeshType.Tight)
                        if (IsTagPrefixed(packingTag) == AllowTightWhenTagged)
                                return SpritePackingMode.Tight;
                return SpritePackingMode.Rectangle;
        }
}


如下图所示,SpritePacker就多出了一个打包图集的选项。



有可能我们会同时把很多图片都拖入unity中,虽然可以全选在设置图片的pack tag,但是我觉得最好全自动完成,比如我们把图片放在不同的文件夹下,那么文件夹的名子就可以用做Atals的名子。最后在分享一条这样的脚本。

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
 
public class  Post : AssetPostprocessor
{
 
        void OnPostprocessTexture (Texture2D texture)
        {
                string AtlasName =  new DirectoryInfo(Path.GetDirectoryName(assetPath)).Name;
                TextureImporter textureImporter  = assetImporter as TextureImporter;
                textureImporter.textureType = TextureImporterType.Sprite;
                textureImporter.spritePackingTag = AtlasName;
                textureImporter.mipmapEnabled = false;
        }
 
}

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引