文章目录
- 前言
- 一、UI图集的压缩
- unity2020之前的版本使用图集
- unity2020之后的版本使用图集
- 二、非UI图集压缩
- 总结
前言
为降低DrawCall,我们需要将多个图片构建在图集上。同时还有个好处,可以自动补齐图片补齐2的幂次方或正方形图,这样便可以进行ETC和PVRTC压缩了。
官方解释请注意 Sprite Packer 在 Unity 2020.1 和更新版本中已弃用,并且将不再作为精灵打包模式的可用选项。现有已使用 Sprite Packer 的项目仍然可以继续使用它,但是在 2020.1 以后创建的任何新项目在打包纹理时将默认使用 Sprite Atlas 系统。
一、UI图集的压缩
如果是UI图片,设置了相同packingTag的Sprite会合并在一个图集,但是游戏中有很多本身就很大的图片,比如背景图或者大头像图。由于这些图片不一定是2的幂次方或正方形图,所以我们可以自动给它们设置成一个唯一的packingTag,这样它们也可以进行压缩了。
如果有些大图需要设置成了RGBA32或者RGBA16,并且自身并不是2的幂次方或者正方形图的话,在去加pakcingTag就不太合适了,这样只会让图片变得更大。所以,在自动构建图集的时候可以做个判断,当图片出现这类情况时不再构建图集。
首先打开图集模式
内部选项,根据需要选择
在包管理器安装2D Sprite插件包
unity2020之前的版本使用图集
设置PackingTag
using System;
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;public class CustomPackerPolicySample : UnityEditor.Sprites.IPackerPolicy
{bool UnityEditor.Sprites.IPackerPolicy.AllowSequentialPacking {get {return true;}}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;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.ETC_RGB4 && fmt <= TextureFormat.ETC2_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.PackerJobjob, 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;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;entry.settings.allowsAlphaSplitting = ti.GetAllowsAlphaSplitting();entry.atlasName = ParseAtlasName(ti.spritePackingTag);entry.packingMode = GetPackingMode(ti.spritePackingTag,tis.spriteMeshType);entry.anisoLevel = ti.anisoLevel;entries.Add(entry);}Resources.UnloadAsset(ti);}//将相同图集的名称划分成不同图集var atlasGroups =from e in entriesgroup e by e.atlasName;foreach(var atlasGroup in atlasGroups){int page = 0;//相同的图集中压缩格式不同的图划分成不同的组var settingsGroups =from t in atlasGroupgroup t by t.settings;foreach(var settingsGroup in settingsGroups){//已经设置了非压缩的图,这里不做成图集,避免图片变大bool skipAtlas = (settingsGroup.Count() == 1 && !IsCompressedFormat(settingsGroup.ElementAt(0).settings.format));if(skipAtlas) {continue;}string atlasName = atlasGroup.Key;if(settingsGroups.Count() > 1)atlasName += string.Format("(Group {0})", page);UnityEditor.Sprites.AtlasSettings settings = settingsGroup.Key;settings.anisoLevel = 1;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, SpriteMeshTypemeshType){if(meshType == SpriteMeshType.Tight)if(IsTagPrefixed(packingTag) == AllowTightWhenTagged)return SpritePackingMode.Tight;return SpritePackingMode.Rectangle;}
}
//如果打包前需要自动指定策略,可以强制设置本地打包使用什么图集策略,然后将策略以及打包平台传入即可static private void BuildAtlas(BuildTarget buildTarget){Packer.SelectedPolicy = typeof(CustomPackerPolicySample).Name;Packer.RebuildAtlasCacheIfNeeded(buildTarget);}
unity2020之后的版本使用图集
创建图集
图集制作
使用方法
SpriteAtlas spriteAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/Art/xxxx");Sprite sprite = spriteAtlas.GetSprite("xxx")
具体的封装,请根据项目自行调整。
二、非UI图集压缩
如果美术人员没有提供符合2的幂次方或正方形要求的图片,那么这些角色、特效和场景图可能无法进行有效压缩。但是,在图形编辑软件中,可以通过在"Advanced"下拉面板中选择适当的"Non Power of 2"选项来强制将这些图片调整为2的幂次方大小。
在这个选项中,"ToNearest"会将图片大小调整到最接近的2的幂次方,"ToLarger"会将图片大小调整到大于等于原始大小的最小2的幂次方,而"ToSmaller"则会将图片大小调整到小于等于原始大小的最大2的幂次方。通过这些选项,可以自动将图片拉伸到符合规则的大小,从而使图片能够进行有效压缩,提高游戏性能和效率。
总结
该篇分享了关于Unity中图集压缩的技巧,包括UI图集和非UI图集的处理方法。通过设置packingTag和在图形编辑软件中调整图像大小的方法,大家可以学会如何有效地压缩游戏中的图像资源,提高游戏性能和效率。希望大家可以通过学习这些技能来优化自己的开发工作。不断学习和探索,打造出更出色的作品!