最近超累,还得再苦逼一段时间。 抽空更新一下博客,希望大家不要忘记我。前段时间写过一篇处理游戏中的大图片进行压缩的文章。
http://www.xuanyusong.com/archives/4312
在处理大图片的时候,为了保证每张图片都会压缩,所以我会自动给每个图片添加一个packingTag,如此一来即使美术出的图片不是2的幂次方,unity也会将它拉成2的幂次方,在ios平台会自动变成正方形,这样就能保证每张图片都可以进行压缩。
Android采用的是这个方式,单个的大图我都会设置一个packingTag 保证每张图片都可以压缩,效果确实还可以。
http://www.xuanyusong.com/archives/4279
IOS的大图就就略显尴尬,因为有些透明渐变的图片,Android使用上述的压缩方式是没问题的,但是IOS如果直接用pvrtc 4来压缩,效果就不太好了。这时候android可以保持原样,ios希望采取 rgba 16bit 的格式,但是因为前面我们给这个图片设置了packingTag ios上会被拉成正方形,那么rgba 16bit就会比图片原始尺寸更加的占内存。可是如果我把packingTag清空,那么android ios两边无法保持一致,如果打包预处理的话,svn就会发生变化。
所以希望,如果图集中只有一张图片,并且设置了非压缩格式,那么即使设置了packingTag也不对它打图集。研究了一下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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
using System; using System.Linq; using UnityEngine; using UnityEditor; using System.Collections.Generic; public class CustomPackerPolicySample : UnityEditor.Sprites.IPackerPolicy { protected class Entry { public Sprite sprite; public UnityEditor.Sprites.AtlasSettings settings; public string atlasName; public SpritePackingMode packingMode; public int anisoLevel; } private const uint kDefaultPaddingPower = 3; // Good for base and two mip levels. public virtual int GetVersion() { return 1; } protected string TagPrefix { get { return "[RECT]"; } } protected bool AllowTightWhenTagged { get { return true; } } protected bool AllowRotationFlipping { get { return true; } } public static bool IsCompressedFormat(TextureFormat fmt) { if (fmt >= TextureFormat.DXT1 && fmt <= TextureFormat.DXT5) return true; if (fmt >= TextureFormat.DXT1Crunched && fmt <= TextureFormat.DXT5Crunched) return true; if (fmt >= TextureFormat.PVRTC_RGB2 && fmt <= TextureFormat.PVRTC_RGBA4) return true; if (fmt == TextureFormat.ETC_RGB4) return true; if (fmt >= TextureFormat.ATC_RGB4 && fmt <= TextureFormat.ATC_RGBA8) return true; if (fmt >= TextureFormat.EAC_R && fmt <= TextureFormat.EAC_RG_SIGNED) return true; if (fmt >= TextureFormat.ETC2_RGB && fmt <= TextureFormat.ETC2_RGBA8) return true; if (fmt >= TextureFormat.ASTC_RGB_4x4 && fmt <= TextureFormat.ASTC_RGBA_12x12) return true; if (fmt >= TextureFormat.DXT1Crunched && fmt <= TextureFormat.DXT5Crunched) return true; return false; } public void OnGroupAtlases(BuildTarget target, UnityEditor.Sprites.PackerJob job, int[] textureImporterInstanceIDs) { List<Entry> entries = new List<Entry>(); foreach (int instanceID in textureImporterInstanceIDs) { TextureImporter ti = EditorUtility.InstanceIDToObject(instanceID) as TextureImporter; TextureFormat desiredFormat; ColorSpace colorSpace; int compressionQuality; ti.ReadTextureImportInstructions(target, out desiredFormat, out colorSpace, out compressionQuality); 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 = desiredFormat; entry.settings.colorSpace = colorSpace; // Use Compression Quality for Grouping later only for Compressed Formats. Otherwise leave it Empty. entry.settings.compressionQuality = IsCompressedFormat(desiredFormat) ? compressionQuality : 0; entry.settings.filterMode = Enum.IsDefined(typeof(FilterMode), ti.filterMode) ? ti.filterMode : FilterMode.Bilinear; entry.settings.maxWidth = 2048; entry.settings.maxHeight = 2048; entry.settings.generateMipMaps = false; entry.settings.enableRotation = AllowRotationFlipping; entry.settings.paddingPower = (uint)EditorSettings.spritePackerPaddingPower; //#if ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION entry.settings.allowsAlphaSplitting = ti.GetAllowsAlphaSplitting (); //#endif //ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION entry.atlasName = ParseAtlasName(ti.spritePackingTag); entry.packingMode = GetPackingMode(ti.spritePackingTag, tis.spriteMeshType); entry.anisoLevel = ti.anisoLevel; 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) { //已经设置了非压缩的图,不做成图集,避免拉成图集占内存。 bool skipAtlas = (settingsGroup.Count () == 1 && !IsCompressedFormat (settingsGroup.ElementAt (0).settings.format)); if (skipAtlas) { Debug.Log (settingsGroup.ElementAt (0).sprite.name); continue; } string atlasName = atlasGroup.Key; if (settingsGroups.Count() > 1) atlasName += string.Format(" (Group {0})", page); UnityEditor.Sprites.AtlasSettings settings = settingsGroup.Key; settings.anisoLevel = 1; // Use the highest aniso level from all entries in this atlas if (settings.generateMipMaps) foreach (Entry entry in settingsGroup) if (entry.anisoLevel > settings.anisoLevel) settings.anisoLevel = entry.anisoLevel; job.AddAtlas(atlasName, settings); 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; } } |
图片如果控制不好,还是很占内存的。我们游戏默认就把所有图片全部压缩,如果美术觉得某些图片效果不好,那么就对它单独处理一下即可。
版本unity5.5.2
最后欢迎大家在下面留言一起讨论。。
- 本文固定链接: https://www.xuanyusong.com/archives/4417
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
雨松,请教个问题。我unity发布iOS游戏的时候 怎么操作可以像王者荣耀一样 homebar向上拖动两次才激活系统的最小化?谢谢
您的文章写得很好,我先把你的文章往外面扩展一下,我还有很多同学也是学习这块,都很赞同您说的,因为您说的都很对!
大神,Unity导出的iOS工程可以被制作成iOS的framework让其他APP使用吗?例如导入了这个framework,点一个按钮就可以将Unity视图显示出来,不需要修改原有main函数。谢谢大神!
你的MMORPG上线了吗?