유니티

[유니티6] 스프라이트 아틀라스(Sprite Atlas) 사용법 및 주의점 (유니티 최적화)

yamaeking 2025. 4. 18. 19:22

printf("Hello world!\n");

 

보통 2D 게임을 만들 때, 렌더링 시 어떤 스프라이트를 참고하여 Draw 하게 되는데 이때 Drawcall이라는 것을 한 번 호출하게 된다. 근데 예를 들어 아래와 같이 그릴 것들이 많아서 참고해야 할 스프라이트 이미지가 n개라고 한다면? Drawcall도 n번 만큼 발생하게 되는 것이다.

 

Drawcall 이 많으면 게임 퍼포먼스가 안 좋아진다. 반대로 얘기하면 Drawcall이 적으면 게임 퍼포먼스가 좋아진다.

 

 

스프라이트 아틀라스를 이용하여 이 Drawcall을 줄여보도록 하자!

 


<기본 설정>

> 유니티6에서는 따로 설정을 하지 않아도 Sprite Atlas를 바로 사용할 수 있다. 아래처럼 바로 Create 할 수 있는데, 이전 버전에서는 Editor에서 어떤 설정을 하여야 저렇게 Create에서 Sprite Atlas 를 사용할 수 있었다라고 한다. (본인은 그땐 안 해봄ㅇㅇ;)

 

 

<Editor 설정>

 

> 보통 유니티6에서는 Sprite Atlas 모드가 V2 -> Enabled 로 되어 있을텐데, 혹시나 안 되어 있다면 체크해주자.

> V1,V2~ 이런 설정들이 있는데 간략하게 설명하자면 아래와 같다. 

항목 Sprite Atlas V1 Sprite Atlas V2
출시 버전 Unity 2017~2018 Unity 2019.3 이상
관리 방식 Built-in 방식 ScriptableObject 기반
Addressable 호환 제한적 완전 지원
AssetBundle 연동 수동 조작 필요 자동 연동 가능
Atlas Packing Editor에서 고정 방식 Build 시점에 유연하게 변경 가능
API SpriteAtlasUtility SpriteAtlasManager 중심으로 개선
권장 여부 더 이상 권장되지 않음 현재 표준 방식

 

옵션 이름 사용되는 Sprite Atlas 버전 에디터에서 사용
Disabled 없음 사용 안 함
Sprite Atlas V1 – Enabled For Builds V1 (구버전) 사용 안 함
Sprite Atlas V1 – Always Enabled V1 (구버전)  사용
Sprite Atlas V2 – Enabled V2 (신버전) 사용
Sprite Atlas V2 – Enabled For Builds V2 (신버전) 사용 안 함
*Sprite Atlas V2 - Enabled 쓰면 된다. (참고로 V1과 V2는 서로 호환되지 않음.)

 

 

 

 

 

실제 사용

기본적인 사용법은 아래와 같다.

  • Assets 아래에 SpriteAltasses 같은 폴더를 하나 만든다. (굳이 안 만들어도 되기는 한데 관리상..)
  • 폴더 내에서 마우스 오른쪽 클릭 -> Create -> 2D -> Sprite Atlas를 만든다.
  • 만들어진 Sprite Altas 에 Sprites 를 추가한다. 
  • 실제 사용하는 곳에서 SpriteAtlas를 불러와 이미지 이름에 해당하는 Sprite를 불러온다.

 

<Sprites 들 넣기>

 

> Atlas 생성하였으면, Atlas를 클릭하여 Inspector 창을 보자. 그러면 저렇게 Objects for Packing 이라는게 있는데, 거기서 +를 눌러 스프라이트들을 추가할 수 있다.

  • 팁 : 아래와 같이 폴더 자체를 통째로 넣을 수 있음.

 

  • 주의점 : 아틀라스에 넣으려고 하는 Sprite 이미지들은 꼭 Sprite Mode를 Single로 해라... Mutiple로 되어 있으면 나중에 스프라이트 불러올 때 이름이 이상하게 되어 있어서 '이거 이름 맞는데 왜 안 불러와짐?ㅡㅡ' 하며 혈압 오를 수도 있다.

 

 

> 대충 스프라이트 낑겨 넣었으면 Atlas에서 Pack Preview 를 클릭하여 적용 완료하자.

 

> 그러면 아래 Preview에서 Atlas화 된 sprite가 보일 것이다. 

> 아틀라스한 이미지가 이상한 방향으로 돌아가 있을 수가 있는데, 그럴 때는 위에서 Allow Rotation 옵션을 꺼주면된다. (* tight packing은 스프라이트의 실제 알파 영역만 기준으로 경계(Rect)를 잡아서 아틀라스에 최대한 촘촘하게 배치하는 방식 )

모드 설명
기본 (Tight Packing 꺼짐) 이미지 외곽 전체를 네모로 잘라서 배열
ight Packing 켜짐 실제 픽셀이 있는 부분만 사용하여 더 촘촘히 배치

 

 

> 여기까지 되었으면 'Addressable' 도 체크해주자.

Addressble 해주면 여러 이점이 있는데, 아래와 같이 안 했을 때와 차이를 정리하였으니 참고 바란다.

항목 Addressable 사용 Addressable 미사용
✅ 로딩 방식 Addressables.LoadAssetAsync<SpriteAtlas>("key") Resources.Load<SpriteAtlas>("path") or Inspector 참조
✅ 로드 제어 비동기(async), 콜백/Task 지원 동기(synchronous), 즉시 반환
✅ 메모리 관리 명시적 Release() 가능 → 메모리 절약 자동 언로드 불가, 메모리 계속 점유
✅ 빌드 최적화 필요한 리소스만 번들화 (필요한 시점에 로드) 전부 빌드에 포함 (Include in Build 체크됨)
✅ 앱 실행 크기 최초 실행 시 가볍고 빠름 실행 크기 증가 가능성 ↑
✅ 유지보수성 Key 기반으로 관리 → 디커플링 용이 경로 기반 → 경로/이름 변경 시 의존성 깨짐
✅ 에셋 번들 분리 배포 가능 (DLC, Patching 등) 불가능 (모든 리소스 포함된 단일 빌드)
❌ 초기 셋업 다소 복잡 (Profile, Group, 키 설정 필요) 단순 (Resources 폴더 or 직접 참조)
❌ 디버깅/테스트 로컬, Remote 빌드 구분 필요 Unity Editor에서 바로 테스트 용이
❌ 런타임 관리 로드/해제 수동 관리 필요 자동 로드 & 해제 (하지만 예측 어려움)

 


<본격 스프라이트 아틀라스 사용하기>

> 그러면 본격적으로 아틀라스를 사용해보자. 본인은 UIHelper라는 클래스를 통해서 Atlas를 캐싱하여 사용한다.

public class UIHelper
{
    public SpriteAtlas _itemAtlas; //아틀라스 부분
    public Dictionary<string, Sprite> _itemSpriteDict = new Dictionary<string, Sprite>();

    public EnchantColorTable colorTable;

    static UIHelper s_instance;
    public static UIHelper Instance { get { Init(); return s_instance; } } //싱글톤


  public Sprite GetItemSprite(string itemName)
  {
      if(_itemAtlas == null)
      {
          Debug.Log("UPHelper : atlas 아직 로딩 안됨!");
          return null;
      }

      return _itemAtlas.GetSprite(itemName);
  }
}

 

보면 _itemAtlas 라는 SpriteAtlas 가 있는데, SpriteAtlas를 먼저 게임 시작하는 곳(예를 들면 타이틀 화면에서 로비로 진입할 때?)에서 비동기로 로드해와야 한다. 어디서 할까 하다가 그냥 BaseScene (모든 Scene에서 달라붙어 있는 컴포넌트) 에서 하기로 하였다. 

using System;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.U2D;

public class BaseScene : MonoBehaviour
{

    private void Start()
    {
        Init();
    }

    protected virtual async void Init()
    {

        try
        {
            await LoadAtlas();
        }
        catch(Exception e)
        {
            Debug.Log($"Atlas load 실패 {e}");
        }

    }



    async Task LoadAtlas()
    {
        var handle = Addressables.LoadAssetAsync<SpriteAtlas>("GameItems");
        if (UIHelper.Instance._itemAtlas == null)
            UIHelper.Instance._itemAtlas = await handle.Task;

        if (UIHelper.Instance._itemAtlas == null)
            Debug.LogError("Sprite Atlas GameItems 로딩 실패");
    }



}

 

 > 대충 이런 식으로 만들면 된다. Addressable이 아니었다라면 Resources.Load<SpriteAtlas>(경로) 형태로 불러와야 하는데, Addressable 을 체크하면 위처럼 그냥 키(이름)만 가지고도 불러올 수 있음ㅇㅇ;

 

> SpriteAtlas 이미지들을 다 불러왔으면 이제 실제 사용하면 되는데, 사용하는 곳에서 그냥  itemImage.sprite = UIHelper.Instance.GetItemSprite(itemName); 이런 식으로 호출하면 된다. 

*ItemName은 실제 스프라이트 이미지의 이름이다. (string)

SpriteAtlas는 저장한 이미지들을 이미지 이름(순수 이름, .png 이런거 안 붙임.)을 key로 저장한다.
그래서 불러올 때도 이미지 이름으로만 불러와도 됨.

 

근데 본인은 이렇게 했는데 자꾸 안돼서 뭐가 문제인지 한 참 헤맸다. 결론은.. 아까도 얘기한 거긴 한데,

 

 --->>>>> SPRITE ATLAS에 쓸 이미지들은 꼭 MULTIPLE 이 아니라, SINGLE로 해라. 두 번해라.

>> Mutiple 로 하면, 실제 이미지 이름이 abc 라고 한다면 abc로 저장되는게 아니고 abc_01, abc_02  이딴 식으로 저장 됨.(dunno y;)