上篇文章说了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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
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的名子。最后在分享一条这样的脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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; } } |
好了,今天比较高兴,入手了ipad air2 嘿嘿嘿~~ 欢迎大家在下面给我留言我们一起讨论。
- 本文固定链接: https://www.xuanyusong.com/archives/3315
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
ios下spritePacker 图片失真请问怎么解决
改成astc 4×4 就可以
Personal版本是不是不支持这个Feature?
http://blog.csdn.net/huutu/article/details/45564555 我想很多人会找 图片批量导入时 格式从texture到sprite(2d and ui)自动转化
UGUI如何使用DDS图片格式呢?
请问MOMO利用这个方法,打包时散的图片还会打包吗?如果不打包那他们去了哪里啊
可能会有三图 没有设置tag name的话
请问MOMO利用了这个方法,打包时还会打包出散的图片吗?
大神~UI用紧缩模式打包后会串图。怎么解决呀?Image的Shader不支持紧缩裁剪,SpirteRenderer的就可以?
momo,在UGUI中,有透明通道的图,只能压成etc2。NGUI的做法Ugui上不好实现,但是有些手机又不支持etc2.请问你们有遇到过这个问题么?
5.3.0以后的,atlas, android选择etc1 后可以勾选split alpha,unity会自动处理这部分
雨松大神,之前听说NGUI需要将图集打包成正方形才能在苹果设备上用。但是UGUI的默认不能打包成正方形了,我现在5.3.4f1的版本,你有办法吗。我还听说现在UGUI不用打正方形了,是真的吗
如果不用 pvr压缩了就可以不用正方形了。。 不过可以设置图集大小 格式的参数。。
嗨~鱼松MM 我有两个问题想请教下1.我把2张图的packing tag设置成不一样的测试发现UGUI也能合并成1个pass call。2.UGUI的图集是否进入游戏的时候就全部加载进内存里了
ugui不会全都载入内存。。
雨松大师你好,请问Unity自带打包工具,如何保留每个小图片周边的透明像素?
请问下,你这个有解决了吗?
请问图集如何热更新呢?
如果使用spritepacker的话,安卓想使用etc1好像不行,没法拿到图集做透明贴图
请问雨松大大,使用UGUI自带的打包图集方式怎么才能知道这个图集有好多M?就像查看单个图片的时候会显示占用多少M一样?
profiler里能看
[熊猫] 哇,好激动,大大这么快就回复我了,但是profiler里面看到的是运行时的大小,也是包里面的大小吗?
profiler看到的是内存大小。。。 包的大小大概是文件大小/3
恩,好奇怪哟,明明打到图集里面,但是在查看profiler的时候,会有图集,也会有单个小图。。。而那些单个小图我都是设了tag的,,,咋回事哟?
请教一个问题,将一组动画序列打包成一个图集后,如何通过代码动态访问呢?是否需要通过TexturePacker打包成图集放在Resource下才能在代码里访问呢?谢谢了~
通过key value的形式关联在prefab里。 然后把prefab放在resources里。 而sprite放在resources外面
这个方法很巧妙!在您的实战经验中,图集是交给unity自动打包多还是自己打包多呢?unity打包的图集我们操作不到,也不能压缩,如果是自己打包的图集就可以压缩了(tinypng),自己打会不会比较好呢?
图集是教给unity自己打包。 我做的就是 当图片放到指定文件夹下。 会根据文件夹自动生成一个prefab然后序列化好key 和 value
能否分享一下key value的脚本做法~ [嘻嘻]
等有空我整理一下在分享吧。
这个办法好 用了~~
大神,问下为什么我没设置packtag之前用assetbundle打出来时99k。设置tag后打出来反而变大成200多K了?按理说打成一张图,应该多余的透明区域都被去掉,应该会更小才对。何解?
碎图打包后变成2的幂的图。确实变大了。。。用unity打出来的资源比TexturePacker以同样的压缩格式打出来的要大很多。原因不明。。。
TextureImportInstructions ins = new TextureImportInstructions(); 5.0版本这个类删除了 该怎么写 谢谢
直接用AtlasSettings
请问有没有监听pack结束的方法
为什么要这么做?