UGUI研究院之SpritePacker打包参数(四)
上篇文章说了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文件夹下, 在代码里面就可以设置图集的属性了。
1 using System; 2 using System.Linq; 3 using UnityEngine; 4 using UnityEditor; 5 using UnityEditor.Sprites; 6 using System.Collections.Generic; 7 8 // DefaultPackerPolicy will pack rectangles no matter what Sprite mesh type is unless their packing tag contains "[TIGHT]". 9 class DefaultPackerPolicySample : UnityEditor.Sprites.IPackerPolicy 10 { 11 protected class Entry 12 { 13 public Sprite sprite; 14 public AtlasSettings settings; 15 public string atlasName; 16 public SpritePackingMode packingMode; 17 } 18 19 public virtual int GetVersion() { return 1; } 20 21 protected virtual string TagPrefix { get { return "[TIGHT]"; } } 22 protected virtual bool AllowTightWhenTagged { get { return true; } } 23 24 public void OnGroupAtlases(BuildTarget target, PackerJob job, int[] textureImporterInstanceIDs) 25 { 26 List<Entry> entries = new List<Entry>(); 27 28 foreach (int instanceID in textureImporterInstanceIDs) 29 { 30 TextureImporter ti = EditorUtility.InstanceIDToObject(instanceID) as TextureImporter; 31 32 TextureImportInstructions ins = new TextureImportInstructions(); 33 ti.ReadTextureImportInstructions(ins, target); 34 35 TextureImporterSettings tis = new TextureImporterSettings(); 36 ti.ReadTextureSettings(tis); 37 38 Sprite[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(ti.assetPath).Select(x => x as Sprite).Where(x => x != null).ToArray(); 39 foreach (Sprite sprite in sprites) 40 { 41 //在这里设置每个图集的参数 42 Entry entry = new Entry(); 43 entry.sprite = sprite; 44 entry.settings.format = ins.desiredFormat; 45 entry.settings.usageMode = ins.usageMode; 46 entry.settings.colorSpace = ins.colorSpace; 47 entry.settings.compressionQuality = ins.compressionQuality; 48 entry.settings.filterMode = Enum.IsDefined(typeof(FilterMode), ti.filterMode) ? ti.filterMode : FilterMode.Bilinear; 49 entry.settings.maxWidth = 1024; 50 entry.settings.maxHeight = 1024; 51 entry.atlasName = ParseAtlasName(ti.spritePackingTag); 52 entry.packingMode = GetPackingMode(ti.spritePackingTag, tis.spriteMeshType); 53 54 entries.Add(entry); 55 } 56 57 Resources.UnloadAsset(ti); 58 } 59 60 // First split sprites into groups based on atlas name 61 var atlasGroups = 62 from e in entries 63 group e by e.atlasName; 64 foreach (var atlasGroup in atlasGroups) 65 { 66 int page = 0; 67 // Then split those groups into smaller groups based on texture settings 68 var settingsGroups = 69 from t in atlasGroup 70 group t by t.settings; 71 foreach (var settingsGroup in settingsGroups) 72 { 73 string atlasName = atlasGroup.Key; 74 if (settingsGroups.Count() > 1) 75 atlasName += string.Format(" (Group {0})", page); 76 77 job.AddAtlas(atlasName, settingsGroup.Key); 78 foreach (Entry entry in settingsGroup) 79 { 80 job.AssignToAtlas(atlasName, entry.sprite, entry.packingMode, SpritePackingRotation.None); 81 } 82 83 ++page; 84 } 85 } 86 } 87 88 protected bool IsTagPrefixed(string packingTag) 89 { 90 packingTag = packingTag.Trim(); 91 if (packingTag.Length < TagPrefix.Length) 92 return false; 93 return (packingTag.Substring(0, TagPrefix.Length) == TagPrefix); 94 } 95 96 private string ParseAtlasName(string packingTag) 97 { 98 string name = packingTag.Trim(); 99 if (IsTagPrefixed(name)) 100 name = name.Substring(TagPrefix.Length).Trim(); 101 return (name.Length == 0) ? "(unnamed)" : name; 102 } 103 104 private SpritePackingMode GetPackingMode(string packingTag, SpriteMeshType meshType) 105 { 106 if (meshType == SpriteMeshType.Tight) 107 if (IsTagPrefixed(packingTag) == AllowTightWhenTagged) 108 return SpritePackingMode.Tight; 109 return SpritePackingMode.Rectangle; 110 } 111 }
如下图所示,SpritePacker就多出了一个打包图集的选项。
有可能我们会同时把很多图片都拖入unity中,虽然可以全选在设置图片的pack tag,但是我觉得最好全自动完成,比如我们把图片放在不同的文件夹下,那么文件夹的名子就可以用做Atals的名子。最后在分享一条这样的脚本。
1 using UnityEngine; 2 using System.Collections; 3 using UnityEditor; 4 using System.IO; 5 6 public class Post : AssetPostprocessor 7 { 8 9 void OnPostprocessTexture (Texture2D texture) 10 { 11 string AtlasName = new DirectoryInfo(Path.GetDirectoryName(assetPath)).Name; 12 TextureImporter textureImporter = assetImporter as TextureImporter; 13 textureImporter.textureType = TextureImporterType.Sprite; 14 textureImporter.spritePackingTag = AtlasName; 15 textureImporter.mipmapEnabled = false; 16 } 17 18 }
好了,今天比较高兴,入手了ipad air2 嘿嘿嘿~~ 欢迎大家在下面给我留言我们一起讨论。
转载于 雨松MOMO程序研究院