赞
踩
图集是将许多较小的,独立的纹理合并到一个较大的纹理文件中,从而最小化材质的数量,因此最小化所需使用的Draw Call数量。这是利用动态批处理的有效方法。
每个独特的材质都需要额外的Draw Call,但是每种材质只支持单一的主纹理。当然,它们也可以支持多个二级纹理,比如法线纹理和发射纹理。然而,将多个主纹理合并到一个大的纹理文件中,渲染这个纹理的对象时,可以最小化所使用的Draw Call数量。
⚠️ :图集只是当所有给低昂的纹理需要相同的着色器时采用的一种方法,如果一些纹理需要通过着色器应用独立的图形效果,它们就必须分离到自己的材质中,并在单独的组中打图集。
游戏大厅需要这么多张图片:
如果我么单张使用,这就存在上面说的三个问题了:多个DrawCall,效率降低,包体变大。
为了解决这三个问题,图集的存在就变得有意义了。那么可能就有同学要问了,图片是美术给的,那么图集也由美术打包,这样可行吗?
答案是:可行,但有一定的限制。
这是美术将所有用到的图片放在一起打包的图集:
我们在使用的时候需要自己拆分,这样使用起来就不是很方便了。最关键的是以后大厅随便添加或者修改一张图都需要美术给我们一整张图集,这样明显是不合理的。 所以只有当场景资源固定了,以后不会在有任何改动的情况下,是可以由美术出图集的。
但是,稍微有点经验的程序员都不会使用上述这种情况。因为项目本身不被修改那几乎是不可能的,有的时候不但要改,而且还要大改;所以将打包图集放在程序上来出来也是更方便,更合理的,下面我们就来一起学习一下Unity的图集吧。
在Unity2020 之后,需在PackageManager中安装2DSprite包,否则无法创建Sprite Atlas
菜单栏 Edit–>Project Settings–>Editor–>EditorSettings–>Sprite packer
Mode:
Project视图右键,Create–>Sprite Atlas
属性 | 功能 |
---|---|
Type | 将“Sprite Atlas”类型设置为Master 或Variant ,Master是默认类型设置,Variant设置一般用于高清/低清资源切换。下面会有一个示例帮助理解。 |
Include in build | 选中此框可将Sprite Atlas资源包括在当前构建中。 |
Allow Rotation | 选中此框可以在Unity将精灵打包到精灵地图集时允许精灵旋转。开启后图集会根据计算将一些精灵旋转排列,这样使得图集更小更紧密。被旋转的精灵在场景被使用时也会对应旋转,这样处理起来就会很麻烦,建议禁用 |
Tight Packing | 选中此框可根据精灵轮廓而不是默认矩形轮廓来打包精灵。开启后,精灵在图集中密集排列,甚至有时会出现一张图上有另外一张图的边角的情况,建议禁用 |
Padding | 不同UI元素之间的间隔,单位为像素,避免图片之间过近导致显示出问题 |
Read/Write Enabled | 选中此框可以从脚本函数(例如Texture2D.SetPixels代码访问时需要开启)访问纹理数据。开启此属性,Unity将创建纹理数据的副本。所以会增大内存占用。此属性仅对未压缩或DXT压缩的纹理有效,所以需要开启此属性的图片也不能修改压缩格式。 |
Generate Mip Maps | 选择此选项可启用Mip-Map生成。Mip贴图是Texture的较小版本,当Texture在屏幕上很小时会使用。 |
Filter Mode | 选择如何过滤纹理;选择Unity在变换期间拉伸时过滤压缩纹理的方式。此设置覆盖Atlas中任何打包精灵的过滤模式设置。 |
Objects for Packing | 需要打包的UI元素,可以放文件夹或者单个图片,放文件夹可以将文件夹所有的图片打包进这个图集中,图片的格式需要设置为Sprite(2D and UI),一个图集最大的尺寸是2048*2048 |
Objects For Packing:将此列表中的所有项目打包到当前选定的Sprite图集中,点击+加号,则可选择一张图片放入图集中,所有图集选择完毕后,点击Pack Preview结果如下图所示:
Platform-specific overrides panel :为Sprite Atlas的每个目标平台设置分辨率、文件大小以及相关内存大小要求、像素尺寸和纹理质量。该面板允许您覆盖精灵图集包含的各个纹理上的这些设置。
后面那些带有自己平台的标识的,都可以通过勾选Override属性,来设置对应平台的图集属性。
比如:在移动的平台(Android,IOS)需要控制包体,那么可以将图集格式设置为ASCT6x6;而在PC端图片的清晰度比包体大小跟重要,则图集可是就可以设置为RGBA32。
DrawCall是指CPU向GPU发送渲染指令的过程。每个DrawCall表示一次绘制操作,包括将一个或多个三角形渲染到屏幕上。对于游戏开发者来说,DrawCall的数量直接影响着游戏的性能,因为每次DrawCall都需要消耗一定的计算资源。
当没有使用图集时:
4个Iamge的DrawCall为4(其中两个,一个是天空盒一个是默认背景)
使用图集后:
4个Iamge的DrawCall为3
使用图集后加载图片只需加载图片所在图集,通过图集获取图片
GetSprite方法传入对应的Sprite名称,名称为打包时的文件名,如果Sprite的模式是Single,直接传入图片的名字,如果是Multiple,需要加上下划线和对应的索引
using UnityEngine.U2D;
void Start()
{
SpriteAtlas atlas = Resources.Load<SpriteAtlas>("SpriteAtlasTest");
Images[0].sprite = atlas.GetSprite("1");
Images[1].sprite = atlas.GetSprite("2");
Images[2].sprite = atlas.GetSprite("3");
Images[3].sprite = atlas.GetSprite("4");
}
SpriteAtlas spriteAtlas = new SpriteAtlas();
AssetDatabase.CreateAsset(spriteAtlas, "Assets/CzhenyaTest.spriteatlas");
SpriteAtlas spriteAtlas = new SpriteAtlas();
// 获取图集下图片
List<Object> packables = new List<Object>(spriteAtlas.GetPackables());
// 每个图集的所有图片路径
private static List<string> textureFullName = new List<string>();
foreach (string item in textureFullName)
{
// 加载指定目录下的图片
Object spriteObj = AssetDatabase.LoadAssetAtPath(item, typeof(Object));
if (!packables.Contains(spriteObj))
{
// 添加到图集中
spriteAtlas.Add(new Object[] {spriteObj});
}
}
SpriteAtlas spriteAtlas = new SpriteAtlas();
SpriteAtlasPackingSettings packSetting = new SpriteAtlasPackingSettings()
{
blockOffset = 1,
enableRotation = false,
enableTightPacking = false,
padding = 8,
};
spriteAtlas.SetPackingSettings(packSetting);
SpriteAtlas spriteAtlas = new SpriteAtlas();
SpriteAtlasTextureSettings textureSettings = new SpriteAtlasTextureSettings()
{
readable = false,
generateMipMaps = false,
sRGB = true,
filterMode = FilterMode.Bilinear,
};
spriteAtlas.SetTextureSettings(textureSettings);
SpriteAtlas spriteAtlas = new SpriteAtlas();
TextureImporterPlatformSettings platformSetting = atlas.GetPlatformSettings("Android");
platformSetting.overridden = true;
platformSetting.maxTextureSize = 2048;
platformSetting.textureCompression = TextureImporterCompression.Compressed;
platformSetting.format = TextureImporterFormat.ASTC_6x6;
spriteAtlas.SetPlatformSettings(platformSetting);
创建在Editor下面一个所有图片的根目录,然后在根据游戏功能或者面板公用等条件,将同一组图片归类到一个文件夹下。比如:Editor/Textures/Login,Editor/Textures/Lobby
这是我下面Demo中使用的图片路径:Assets/CreateAtlas/Editor/Res/SpriteAtlas
PS:按照设计以后新增的图片都会按照功能再分文件夹放到SpriteAtlas文件夹下。
注意代码放到Editor
文件夹下。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;
public class CreateAtlas : MonoBehaviour
{
/// <summary>
/// 图片根目录 -- 需要打包图集的文件夹父级
/// 适用目录结构:根部文件夹
/// -> 图片文件夹1
/// -> 图片文件夹2
/// ...
/// </summary>
private static string pathRoot = Application.dataPath + "/CreateAtlas/Editor/Res/SpriteAtlas/";
/// <summary>
/// 图集存储路径
/// </summary>Assets/CreateAtlas/Editor/Res/Textures
private static string atlasStoragePath = "Assets/CreateAtlas/Editor/Res/Textures/";
/// <summary>
/// 每个需要打图集的文件夹名 -- 即图集名
/// </summary>
private static string spritefilePathName;
[MenuItem("Tools/打包图集")]
public static void CreateAllSpriteAtlas()
{
Debug.Log("打包图集开始执行");
DirectoryInfo info = new DirectoryInfo(pathRoot);
int index = 0;
// 遍历根目录
foreach (DirectoryInfo item in info.GetDirectories())
{
spritefilePathName = item.Name;
SpriteAtlas spriteAtlas = AssetDatabase.LoadAssetAtPath(atlasStoragePath + "/" + spritefilePathName + ".spriteatlas", typeof(Object)) as SpriteAtlas;
// 不存在则创建后更新图集
if (spriteAtlas == null)
{
spriteAtlas = CreateSpriteAtlas(spritefilePathName);
}
string spriteFilePath = pathRoot + "/" + spritefilePathName;
UpdateAtlas(spriteAtlas, spriteFilePath);
// 打包进度
EditorUtility.DisplayProgressBar("打包图集中...", "正在处理:" + item, index / info.GetDirectories().Length);
index++;
}
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
Debug.Log("打包图集执行结束");
}
/// <summary>
/// 创建图集
/// </summary>
/// <param name="atlasName">图集名字</param>
private static SpriteAtlas CreateSpriteAtlas(string atlasName)
{
SpriteAtlas atlas = new SpriteAtlas();
#region 图集基础设置
SpriteAtlasPackingSettings packSetting = new SpriteAtlasPackingSettings()
{
blockOffset = 1,
enableRotation = false,
enableTightPacking = false,
padding = 8,
};
atlas.SetPackingSettings(packSetting);
#endregion
#region 图集纹理设置
SpriteAtlasTextureSettings textureSettings = new SpriteAtlasTextureSettings()
{
readable = false,
generateMipMaps = false,
sRGB = true,
filterMode = FilterMode.Bilinear,
};
atlas.SetTextureSettings(textureSettings);
#endregion
#region 分平台设置图集格式
TextureImporterPlatformSettings platformSetting = atlas.GetPlatformSettings(GetPlatformName(BuildTarget.iOS));
platformSetting.overridden = true;
platformSetting.maxTextureSize = 2048;
platformSetting.textureCompression = TextureImporterCompression.Compressed;
platformSetting.format = TextureImporterFormat.PVRTC_RGB4;
atlas.SetPlatformSettings(platformSetting);
// 需要多端同步,就在写一份
platformSetting = atlas.GetPlatformSettings(GetPlatformName(BuildTarget.Android));
platformSetting.overridden = true;
platformSetting.maxTextureSize = 2048;
platformSetting.textureCompression = TextureImporterCompression.Compressed;
platformSetting.format = TextureImporterFormat.ASTC_6x6;
atlas.SetPlatformSettings(platformSetting);
#endregion
string atlasPath = atlasStoragePath + "/" + atlasName + ".spriteatlas";
AssetDatabase.CreateAsset(atlas, atlasPath);
AssetDatabase.SaveAssets();
return atlas;
}
/// <summary>
/// 每个图集的所有图片路径 -- 记得用之前清空
/// </summary>
private static List<string> textureFullName = new List<string>();
/// <summary>
/// 更新图集内容
/// </summary>
/// <param name="atlas">图集</param>
static void UpdateAtlas(SpriteAtlas atlas, string spriteFilePath)
{
textureFullName.Clear();
FileName(spriteFilePath);
// 获取图集下图片
List<Object> packables = new List<Object>(atlas.GetPackables());
foreach (string item in textureFullName)
{
// 加载指定目录
Object spriteObj = AssetDatabase.LoadAssetAtPath(item, typeof(Object));
Debug.Log("存png和jpg后缀的图片: " + item + " , " + !packables.Contains(spriteObj));
if (!packables.Contains(spriteObj))
{
atlas.Add(new Object[] { spriteObj });
}
}
}
/// <summary>
/// 递归文件夹下的图
/// </summary>
/// <param name="folderPath"></param>
static void FileName(string folderPath)
{
DirectoryInfo info = new DirectoryInfo(folderPath);
string str = Application.dataPath.Replace(@"/", @"\");
foreach (DirectoryInfo item in info.GetDirectories())
{
FileName(item.FullName);
}
foreach (FileInfo item in info.GetFiles())
{
// 存png和jpg后缀的图片
if (item.FullName.EndsWith(".png", StringComparison.Ordinal)
|| item.FullName.EndsWith(".jpg", StringComparison.Ordinal))
{
textureFullName.Add("Assets" + item.FullName.Replace(str, ""));
}
}
}
/// <summary>
/// 不同平台枚举对应的值
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
static string GetPlatformName(BuildTarget target)
{
string platformName = "";
switch (target)
{
case BuildTarget.Android:
platformName = "Android";
break;
case BuildTarget.iOS:
platformName = "iPhone";
break;
case BuildTarget.PS4:
platformName = "PS4";
break;
case BuildTarget.XboxOne:
platformName = "XboxOne";
break;
case BuildTarget.NoTarget:
platformName = "DefaultTexturePlatform";
break;
default:
platformName = "Standalone";
break;
}
return platformName;
}
}
点击打包图集后,就会把文件夹SpriteAtlas下面的图按照文件夹打包成图集。逻辑执行完成后就会在
Textures文件夹下生成新的图集:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。