스프라이트 패커는 Unity 2020.1 이상에 대해 지원 중단 예정이며, 더 이상 스프라이트 패커 모드에서 옵션으로 사용할 수 없습니다.스프라이트 패커를 이미 사용 중인 기존 프로젝트는 계속 사용할 수 있지만, 2020.1 이후 생성된 새 프로젝트는 텍스처 패킹 시 기본적으로 Sprite Atlas를 사용합니다.
스프라이트 그래픽스를 디자인할 때는 각 캐릭터에 대해 별도의 텍스처 파일로 작업하는 것이 편리합니다.그러나 이 경우 그래픽 요소 사이의 빈 공간이 스프라이트 텍스처의 상당한 부분을 차지하게 되며 이 공간은 런타임 시 비디오 메모리를 낭비하게 됩니다.최적의 성능을 위해서는 여러 스프라이트 텍스처의 그래픽스를 아틀라스라는 단일 텍스처에 최대한 모아 넣는 것이 가장 좋습니다. Unity에서는 스프라이트 패커 유틸리티를 제공하여 개별 스프라이트 텍스처로 아틀라스를 생성하는 과정을 자동화합니다.
Unity가 내부적으로 스프라이트 아틀라스 텍스처의 생성 및 사용을 처리하기 때문에 사용자가 수동으로 할당할 필요가 없습니다. 플레이 모드에 들어갈 때 또는 빌드 중에 아틀라스를 패킹하는 옵션이 있으며 스프라이트 오브젝트용 그래픽스는 일단 아틀라스가 생성되면 아틀라스로부터 얻어오게 됩니다.
텍스처의 스프라이트를 패킹하도록 하려면 텍스처 임포터의 패킹 태그를 지정해야 합니다.
스프라이트 패커는 기본적으로 비활성화되어 있지만 에디터 창(메뉴:Edit > Project Settings로 이동한 다음 Editor 카테고리 선택)에서 설정할 수 있습니다.스프라이트 패킹 모드는 Disabled에서 Enabled for Builds(패킹이 빌드에 사용되지만 플레이 모드에는 사용되지 않음) 또는 Always Enabled(패킹이 플레이 모드와 빌드 모두에 활성화됨)로 변경할 수 있습니다.
Sprite Packer 창(메뉴:Window > 2D > Sprite Packer)을 열고 왼쪽 모서리 상단의 Pack 버튼을 클릭하면 아틀라스 내에 패킹된 텍스처의 배열을 확인할 수 있습니다.
프로젝트 패널에서 스프라이트를 선택하면 아틀라스에서도 해당 포지션이 표시됩니다. 아웃라인은 실제로는 렌더 메시 아웃라인이며 타이트 패킹에 사용되는 영역 또한 정의합니다.
Sprite Packer 창 맨 위에 있는 툴바에는 패킹 및 뷰에 영향을 주는 여러 컨트롤이 있습니다.Pack 버튼을 누르면 패킹 작업이 시작되지만 마지막으로 패킹된 이후 아틀라스가 변경된 적이 없을 경우 강제로 업데이트하지는 않습니다.(아래 스프라이트 패커 커스터마이징에 설명한 것처럼 커스텀 패킹 정책을 구현하면 관련된 Repack 버튼이 표시됩니다.)View Atlas 및 Page # 메뉴를 사용하면 창에 표시할 아틀라스 페이지를 선택할 수 있습니다.(최대 텍스처 크기에 모든 스프라이트를 넣을 공간이 충분하지 않은 경우 단일 아틀라스가 여러 개의 “페이지”로 분할될 수 있음).페이지 번호 옆에 있는 메뉴로 아틀라스에 사용되는 “패킹 정책”을 선택합니다(아래 참조).툴바 오른쪽에는 뷰를 줌하고 아틀라스의 컬러와 알파 디스플레이 간에 전환할 수 있는 컨트롤이 두 개 있습니다.
스프라이트 패커는 패킹 정책을 사용하여 스프라이트를 아틀라스에 할당하는 방법을 결정합니다.패킹 정책을 직접 만들 수 있으며(아래 참조), 언제든지 Default Packer Policy, Tight Packer Policy, Tight Rotate Enabled Sprite Packer Policy 옵션을 사용할 수 있습니다.이러한 정책을 사용하면 텍스처 임포터의 Packing Tag 프로퍼티가 스프라이트가 패킹될 아틀라스의 이름을 직접 선택하므로 패킹 태그가 동일한 모든 스프라이트는 같은 아틀라스에 패킹됩니다.그런 다음 아틀라스는 텍스처 임포트 설정에 따라 추가로 정렬되어 사용자의 소스 텍스처 설정과 일치하게 됩니다.같은 텍스처 압축 설정이 적용된 스프라이트는 가능하다면 동일 아틀라스에 그룹화됩니다.
대부분의 경우 DefaultPackerPolicy 옵션이 적합하지만 필요하다면 직접 커스텀 패킹 정책을 구현할 수도 있습니다.커스텀 정책을 구현하려면 에디터 스크립트의 클래스용 UnityEditor.Sprites.IPackerPolicy 인터페이스를 구현해야 합니다.인터페이스에는 다음 메서드가 있어야 합니다.
DefaultPackerPolicy는 디폴트로 사각 패킹을 사용합니다(SpritePackingMode 참조). 텍스처 공간 효과를 사용하거나 스프라이트 렌더링에 다른 메시를 사용하고자 할 때 유용합니다. 커스텀 정책에서는 이를 오버라이드하여 타이트 패킹을 대신 사용할 수 있습니다.
using System;
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class DefaultPackerPolicySample : 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 virtual string TagPrefix { get { return "[TIGHT]"; } }
protected virtual bool AllowTightWhenTagged { get { return true; } }
protected virtual bool AllowRotationFlipping { get { return false; } }
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 = ti.mipmapEnabled;
entry.settings.enableRotation = AllowRotationFlipping;
if (ti.mipmapEnabled)
entry.settings.paddingPower = kDefaultPaddingPower;
else
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)
{
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;
}
}
using System;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEditor.Sprites;
using System.Collections.Generic;
// TightPackerPolicy will tightly pack non-rectangle Sprites unless their packing tag contains "[RECT]".
class TightPackerPolicySample : DefaultPackerPolicySample
{
protected override string TagPrefix { get { return "[RECT]"; } }
protected override bool AllowTightWhenTagged { get { return false; } }
protected override bool AllowRotationFlipping { get { return false; } }
}
```` using System; using System.Linq; using UnityEngine; using UnityEditor; using UnityEditor.Sprites; using System.Collections.Generic;
// TightPackerPolicy will tightly pack non-rectangle Sprites unless their packing tag contains “[RECT]”. class TightRotateEnabledSpritePackerPolicySample : DefaultPackerPolicySample { protected override string TagPrefix { get { return “[RECT]”; } } protected override bool AllowTightWhenTagged { get { return false; } } protected override bool AllowRotationFlipping { get { return true; } } }
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.
방문하는 모든 웹사이트의 정보가 브라우저에서 쿠키 형태로 저장되거나 수집될 수 있습니다. 본 정보는 귀하와 귀하의 선호도, 기기에 대한 것이며, 귀하의 선호도에 따라 사이트가 동작하도록 하는 데 사용됩니다. 본 정보는 귀하를 직접적으로 식별하지 않으나 보다 개인화된 웹 경험을 제공하기 위해 사용됩니다. 그러나 일부 쿠키를 거부할 수 있습니다. 더 자세한 정보를 확인하고 기본 설정을 변경하려면 해당 카테고리의 제목을 클릭하세요. 그러나 일부 쿠키를 차단하면 귀하의 사이트 경험과 회사에서 제공하는 서비스에 영향을 미칠 수 있습니다.
추가 정보
본 쿠키는 동영상 및 실시간 채팅과 같은 고급 기능과 개인화를 허용합니다. 쿠키는 회사 또는 회사 페이지에 추가된 제3 서비스 사업자가 설정할 수 있습니다. 쿠키를 허용하지 않으면 일부 기능이 정상 작동하지 않을 수 있습니다.
이 쿠키는 방문자 수, 데이터 트래픽 정보를 확인해 회사 사이트의 성능을 측정하고 개선할 수 있도록 합니다. 또한 가장 인기가 많거나 인기가 적은 페이지를 확인하며 방문자가 사이트를 이동하는 방법을 확인할 수 있도록 합니다. 쿠키가 수집하는 모든 정보는 누적되며 익명 처리됩니다. 쿠키를 허용하지 않으면 귀하가 회사 사이트에 방문한 시기를 알 수 없습니다.
이 쿠키는 회사의 광고 협력사가 회사 사이트에 설정한 것입니다. 해당 협력사는 귀하의 관심사에 대한 프로파일을 만들고 다른 사이트에서도 관련 광고를 표시하기 위해 이 쿠키를 사용합니다. 이 쿠키는 귀하의 브라우저와 기기를 식별함으로써 동작합니다. 이 쿠키를 허용하지 않으면 다른 웹사이트에서 회사가 제공하는 맞춤형 광고를 경험할 수 없습니다.
이 쿠키는 웹사이트의 기능을 위해 필수적이며, 회사 시스템 내에서 종료할 수 없습니다. 이 쿠키는 개인정보 선호도, 로그인 또는 양식 작성과 같은 서비스 요청에 해당하는 귀하의 행위에 따라서만 주로 설정됩니다. 귀하의 브라우저에서 이 쿠키를 차단하거나 쿠키에 대해 알림 설정을 할 수 있지만, 이 경우 해당 사이트의 일부 기능이 동작하지 않을 수 있습니다.