范少华的技术学习 Unity Coder

Unity 图集的理解与使用

2019-07-22
FSH

理解图集

  • 所谓图集就是将很多零碎的2d小图整合成一张大图,做成大图后我们不仅会想,为什么这么做呢?这样做有什么好处呢?
  • 图集的优点:
    • 提升效率

      图片尺寸为2的次幂时,GPU处理起来会快很多,小图自己是做不到每张图都是2的次幂的,但打成一张大图就可以(浪费一点也无所谓);

    • UI的合批处理,减少drawcall

      打成图集后,CPU在传送资源信息给GPU时,只需要传一张大图就可以了,因为GPU可以在这张图中的不同区域进行采样,然后拼出对应的界面。注意,这就是为什么一个UI界面需要用同一个图集的原因,是Batch的关键,因为一个Drawcall就把所有原材料传过去了,GPU你画去吧。

    • 避免资源浪费

      我们用来做sprite 的图片,通常会留有很多空白的地方,我们在画完了sprite之后,这些地方很可能就没有什么作用了,打成图集后把图片上的空间尽量利用得充实一点,就可以在一定程度上避免这些浪费。

    但也不可盲目的都打成一个图集,太大了并不好,在后面的注意事项里会详细说明。

打包图集

  • 在Editor模式下,默认是不打图集的(此模式下使用图集比较慢),此时想要打成图集,有两种方法:
    • Edit » Project Seting »Editor»Sprite Packer的Mode需要设置为Always Enabled 即可开启自动打图集
    • 手动利用系统自带的打包工具SpritePacker(也可以使用第三方的工具TexturePacker进行图集制作)
  • SpritePacker打图集时是根据图片的 packing tag 来工作的,它把packing tag相同的sprite打到一个图集里,packing tag如果为空的话,则该图片不会被打到图集里,需要注意的是Resources中的图片不会被打包到图集。
  • 举个例子

    • 三个图的设置为:img1 » packing tag(img1);img2 » packing tag(img2);img3 » 空;此时打了两个图集,分别为img1,img2。img3未达成图集img1,img2为别位于对应的图集里:
    • 三个图的设置为:img1 » packing tag(img1);img2 » packing tag(img2);img3 » packing tag(img3);此时分别打了三个图集:
    • 三个图的设置为:img1 » packing tag(img);img2 » packing tag(img);img3 » packing tag(img),此时只打了一个图集,包含此三张图:

使用图集的注意事项

  • 能够打图集的要求
    • 图片需要设置为精灵模式;
    • 需要指定packing tag,否则不会打进图集;
    • Resources中的图片不会被打包到图集;
  • 图集分类
    • 设计UI时要考虑重用性,如一些边框、按钮等,这些作为共享资源,放在1~3张大图集中,称为重用图集;
    • 其它非重用UI按照功能模块进行划分,每个模块使用1~2张图集,为功能图集;
    • 对于一些UI,如果同时用到功能图集与重用图集,但是其功能图集剩下的“空位”较多,则可以考虑将用到的重用图集中的元素单独拎出来,合入功能图集中,从而做到让UI只依赖于功能图集。也就是通过一定的冗余,来达到性能的提升;

注意控制图集的大小,不要让图集太大,一个超级大图集的DrawCall消耗或许顶的上十几个小图集的消耗

辅助工具

  • 图片导入时自动设置模式,根据文件夹路径设置packing tag
          using UnityEngine;
          using UnityEditor;
    
          public class AutoSpritePacker : AssetPostprocessor
          {
              /// <summary>
              /// 标识是否初次导入
              /// </summary>
              private string m_Version = "1";
              /// <summary>
              /// 最大尺寸,一般为1024,根据自己项目需要设置
              /// </summary>
              private int maxSize = 1024;
    
              /// <summary>
              /// 需要处理的图片根路径(并不是所有的图片都需要这样处理)
              /// 这里是定义出来,项目里一般会有这些资源路径的管理分类,直接获取即可
              /// </summary>
              private string tarPath = "Assets/Picture";
    
              /// <summary>
              /// 得到导入图片的文件夹路径,作为其 packing tag
              /// </summary>
              /// <param name="path"></param>
              /// <returns></returns>
              private string DisposePath(string path)
              {
                  string tempPath = "";
                  tempPath = path.Replace("\\", "/");
                  int lastIndex = tempPath.LastIndexOf(@"/");
                  tempPath = tempPath.Substring(0, lastIndex);
                  return tempPath;
              }
    
              /// <summary>
              /// 图片导入时自动处理
              /// </summary>
              /// <param name="texture"></param>
              void OnPostprocessTexture(Texture2D texture)
              {
                  //判断导入的图片是否在目标路径下
                  if (assetPath.Contains(tarPath))
                  {
                      string packingTag = DisposePath(assetPath);
                      TextureImporter textureImporter = assetImporter as TextureImporter;
    
                      //新导入的
                      if (textureImporter.userData != m_Version)
                      {
                          //设置为精灵模式
                          textureImporter.textureType = TextureImporterType.Sprite;
                          //设置默认格式
                          textureImporter.spriteImportMode = UnityEditor.SpriteImportMode.Single;
                          //设置 packing tag
                          textureImporter.spritePackingTag = packingTag;
                          //默认取消 mipmap(太占内存,需要的话在游戏里针对性处理)
                          textureImporter.mipmapEnabled = false;
                          //标记导入过
                          textureImporter.userData = m_Version;
                          //根据图片是否有透明通道设置alphaIsTransparency
                          textureImporter.alphaIsTransparency = textureImporter.DoesSourceTextureHaveAlpha();
                          //设置特定的目标平台设置
                          TextureImporterPlatformSettings setting = textureImporter.GetDefaultPlatformTextureSettings();
                          //设置最大尺寸
                          setting.maxTextureSize = maxSize;
                          textureImporter.SetPlatformTextureSettings(setting);
                          //保存
                          textureImporter.SaveAndReimport();
                      }
                      //已处理过的(有些是不需要打图集的)
                      else
                      {
                          textureImporter.spritePackingTag = textureImporter.spritePackingTag != string.Empty ? packingTag : string.Empty;
                      }
                      EditorUtility.SetDirty(textureImporter);
                  }
              }
          }
    
  • 打图集时的一些自定义设置

    这个主要没有自己写,参考的雨松大大的博文,很完善,这里就不多做说明了,去这里看吧

补充

Unity2017之后开始使用Sprite Atlas(精灵图集),我也学习了下,大家可以看下我的这篇文章Unity SpriteAtlas的学习


Comments

Content