티스토리 뷰

## Addressables system(주소지정가능 시스템)

- 런타임에 자산을 load 및 release 하기위한 API와 content를 구성 및 패키징하는 tools 및 scripts 제공

- 주소로 Asset을 로드하는 쉬운 방법 제공 (기존 직접참조, Resources폴더, AssetBundle의 상위호환 추상화 계층)

- 자산 호스팅 위치를 코드수정 없이 유연하게 변경 가능(local, CDN 등)

- Dependency management : content를 반환하기 전에 종속된 모든 mesh, shader, animation 등이 로드됨

- Memory management : reference를 자동으로 계산하고 profiler를 통한 메모리 프로파일링 기능 제공

  - 내부적으로 Weak reference 사용?

- 로컬 및 원격 배포용 자산을 쉽고 효율적으로 packing할 수 있도록 지원 (AssetBundles를 기반으로함)

 

 

 

### Package dependencies

실제 닷넷 어셈블리 참조관계
Dependency Assemblies

 

### 주요 키워드

- Address : asset의 위치ID (location identifier) 문자열

- Label : 비슷한 아이템들의 런타임 로딩을 위해 제공되는 추가적인 Addressable Asset ID

- `AssetReference` : addressable asset에 대한 참조. 직접참조처럼 작동하지만 초기화가 지연되는 객체. 요청시 로드할 수 있는 Addressable로 GUID를 저장. 참조가 설정되었는지 `RuntimeKeyIsValid()`를 통해 확인가능.

- `IResourceLocation` : 자산 및 해당 종속성을 로드하기 위한 정보가 포함된 중간 객체

- AddressableAssetData 디렉토리 : 프로젝트의 Assets디렉토리에 저장되는 Addressable Asset metadata 

- Asset group : build-time processing에 사용할 수 있는 Addressable Asset 집합 (Asset group schema로 정의됨)

 

## Addressable Asset 추가 방법

- 인스펙터에서 Addressable 체크박스를 체크시

- 인스펙터에서 `AssetReference`타입의 필드에 에셋 연결시

- Addressables Groups창(Window > Asset Management > Addressables > Group)에 드래그&드랍으로 추가시

- Addressable로 체크한 프로젝트 폴더에 에셋 추가시

 

## Addressable 자산 로드시 내부 수행순서

1. 해당 key에 대한 resource 위치 조회 (`IResourceLocation` key 제외)

2. 종속성(dependencies) 목록 수집

3. 필요한 모든 원격(remote) AssetBundles 다운로드

4. AssetBundles를 메모리에 로드

5. 작업(operation)의 Result객체를 로드된 객체로 설정

6. 작업의 Status를 업데이트하고 `Completed` 이벤트 리스너를 호출

 

## 주요 API

### GameObject

- `GameObject.Instantiate` : 게임오브젝트 인스턴스화

- `GameObject.Destory` : `GameObject.Instantiate`(또는 Addressables가 아닌 방식)로 생성된 객체 인스턴스 제거

 

### Addressables

자산로드 (LoadAssetAsync)

참조카운트 1 증가(매 호출시마다). 최초 1회 로드후 기존 `Instantiate`로 다수의 객체를 참조카운트 증가 없이 인스턴스화할때 유용. (e.g. Object pooling)

- `Addressables.LoadAssetAsync<TObject>` : 단일 에셋 로드

- `Addressables.LoadAssetsAsync<TObject>` : 여러 에셋 로드

  - `releaseDependenciesOnFailure` : 로드 오류 처리 방법 지정. true면 오류 발생시 성공적으로 로드된 작업 및 자산도 모두 중단 및 해제. false면 오류발생한 자산만 null로 해서 모든 작업 완료 후 반환.

- `Addressables.Release` : 작업(operation) 및 관련 리소스 해제

- `Addressables.Release<TObject>` : 에셋 해제

 

자산인스턴스화 (InstantiateAsync)

참조카운트 1 증가(매 호출시마다). 내부적으로 LoadAssetAsync 사용 및 인스턴스화함. persistent scene에 올라가는 manager 인스턴스와 같은 예에서 활용가능

- `Addressables.InstantiateAsync` : 단일객체 로드 및 인스턴스화

  - instantiationParameters : 다수의 인스턴스화에 동일한 인자값 사용시 해당 구조체를 통해 사용

  - trackHandle : 작업핸들을 Addressables시스템에서 추적할지 여부. true시 `Addressables.ReleaseInstance`를 통해 자산 릴리즈 가능(또는 종속된 Scene 언로드시 자동해제됨). false시 작업핸들을 직접 관리 및 해제 필요.

- `Addressables.ReleaseInstance` : `Addressables.InstantiateAsync`로 생성된 객체를 해제(release)하고 제거(destroy)

 

Scene로드 (LoadSceneAsync)

- `Addressables.LoadSceneAsync` : Scene 로드

  - `activateOnLoad` : 로드가 완료되는 즉시 Scene을 활성화할지, `SceneInstance.ActivateAsync` 호출시까지 대기할지 여부 (AsyncOperation.allowSceneActivation과 동일. 기본값은 true. false설정시 Scene이 활성화될때까지 다른 Addressable에셋 로드를 포함하여  `AsyncOperation` 대기열(queue)이 차단됨에 유의)

- `Addressables.UnloadSceneAsync` : `Addressables.LoadSceneAsync`를 통해 로드된 Scene 해제

 

### AssetReference

주로 Scene 등에 미리 직렬화 구성하고 런타임에 Lazy 로드가 필요한 경우 사용. `Addressables`의 LoadAssetAsync, InstantiateAsync, LoadSceneAsync 및 Release API 지원(static method와 instance의 method 차이)

- `assetReference.LoadAssetAsync<TObject>`

- `assetReference.ReleaseAsset`

- `assetReference.InstantiateAsync`

- `assetReference.ReleaseInstance`

- `assetReference.LoadSceneAsync`

 

## Addressables시스템의 참조 카운트 (공식문서, 포럼)

Addressables시스템은 참조카운팅을 사용하여 자산이 사용중인지 여부를 결정하기 때문에 로드(load)하거나 인스턴스화(instantiate)하는 모든 자산은 사용이 끝나면 해제(release)해야함

- `Addressables.LoadAssetAsync` : 참조카운트 1 증가 (이후 `Object.Instantiate` 사용시 카운트는 그대로)

  - 로드된 자산 또는 작업핸들을 해제시 참조카운트가 0이되면 관련된 자산이 언로드되고 모든 인스턴스화된 복사본도 해당 하위 자산을 잃게됨(e.g. Scene에 GameObject는 존재하지만 의존하는 mesh나 texture는 없음)

- `Addressables.InstantiateAsync` : 호출시마다 참조카운트 1 증가. 해제시 개별적으로 `Addressables.ReleaseInstance` 호출

- Scene 언로드시 내부적으로 trackHandle되는 `InstantiateAsync`로 생성된 addressable 인스턴스들은 자동으로 해제됨 

- `LoadAssetAsync`를 통해 로드된 객체(texture, material, game object, etc)는 자동해제되지 않으므로 수동으로 `Release` 호출 필요

 

## 여러 자산 로드시 개별 자산 로드 순서 설정

기본적으로 한 operation에서 여러 자산을 로드할때 개별 자산이 로드되는 순서는 key 목록 순서와 반드시 동일하지 않음

key 목록 순서와 개별 자산 로드 순서를 동기화하고 싶다면 `IResourceLocation`을 사용할 수 있음

 

## 비동기 작업(Operations) 핸들링 방법

### Coroutines and IEnumerator

using System.Collections;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

internal class LoadWithIEnumerator : MonoBehaviour
{
    public string address;
    AsyncOperationHandle<GameObject> opHandle;

    public IEnumerator Start() {
        opHandle = Addressables.LoadAssetAsync<GameObject>(address);

        if (!opHandle.IsDone)
            yield return opHandle;

        if (opHandle.Status == AsyncOperationStatus.Succeeded) {
            Instantiate(opHandle.Result, transform);
        } else {
            Addressables.Release(opHandle);
        }
    }

    void OnDestroy() {
        Addressables.Release(opHandle);
    }
}

 

### C# Event

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

internal class LoadWithEvent : MonoBehaviour
{
    public string address;
    AsyncOperationHandle<GameObject> opHandle;

    void Start() {
        opHandle = Addressables.LoadAssetAsync<GameObject>(address);
        opHandle.Completed += Operation_Completed;
    }

    private void Operation_Completed(AsyncOperationHandle<GameObject> obj) {

        if (obj.Status == AsyncOperationStatus.Succeeded) {
            Instantiate(obj.Result, transform);
        } else {
            Addressables.Release(obj);
        }
    }

    void OnDestroy() {
        Addressables.Release(opHandle);
    }
}

 

### C# Task (async/await)

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

internal class LoadWithTask : MonoBehaviour
{
    // Label or address strings to load
    public List<string> keys = new List<string>() { "characters", "animals" };

    // Operation handle used to load and release assets
    AsyncOperationHandle<IList<GameObject>> loadHandle;

    public async void Start() {
        loadHandle = Addressables.LoadAssetsAsync<GameObject>(
            keys, // Either a single key or a List of keys 
            addressable => {
            // Called for every loaded asset
            Debug.Log(addressable.name);
            }, Addressables.MergeMode.Union, // How to combine multiple labels 
            false); // Whether to fail if any asset fails to load

        // Wait for the operation to finish in the background
        await loadHandle.Task;

        // Instantiate the results
        float x = 0, z = 0;
        foreach (var addressable in loadHandle.Result) {
            if (addressable != null) {
                Instantiate<GameObject>(addressable,
                        new Vector3(x++ * 2.0f, 0, z * 2.0f),
                        Quaternion.identity,
                        transform); // make child of this object

                if (x > 9) {
                    x = 0;
                    z++;
                }
            }
        }
    }

    private void OnDestroy() {
        Addressables.Release(loadHandle); 
        // Release all the loaded assets associated with loadHandle
        // Note that if you do not make loaded addressables a child of this object,
        // then you will need to devise another way of releasing the handle when
        // all the individual addressables are destroyed.
    }
}

Task방식 사용시 `Task`클래스의 method들 사용가능

// Load the Prefabs
var prefabOpHandle = Addressables.LoadAssetsAsync<GameObject>(
    keys, null, Addressables.MergeMode.Union, false);

// Load a Scene additively
var sceneOpHandle 
    = Addressables.LoadSceneAsync(nextScene, 
        UnityEngine.SceneManagement.LoadSceneMode.Additive);

await System.Threading.Tasks.Task.WhenAll(prefabOpHandle.Task, sceneOpHandle.Task);

 

## Scene에서의 Addressabes

- Addressable로 지정된 Scene의 내부 자산들은 암시적으로 종속성이 부여되고 content 빌드를 만들때 Scene과 동일한 AssetBundle에 자산을 압축. 단, non-Addressable이 아닌 개별적으로 Addressable로 지정된 자산들은 속한 그룹에 따라 고유한 AssetBundle에 포함됨.

- non-Addressable로 지정된 Scene 내부에 배치된 Addressable자산은 암시적 종속성이 되어 built-in 데이터에 해당 자산의 사본이 포함됨에 유의 (이 경우, AssetReference를 통해 장면에 미리 구성하고 런타임에 Lazy로드하는 방법 사용가능)

- 둘 이상의 위치에서 사용되는 암시적 종속성은 여러 AssetBundle 및 Scene 내부에 복제될 수 있으므로 Analyze툴의 Check Duplicate Bundle Dependecies rule을 통해 중복을 찾고 제거 필요

 

## Addressable자산 Profiling

- Event Viewer 활성화 : "Window > Asset Management > Addressables > Settings"의 Send Profiler Events 체크

- Event Viewer 사용 : "Window > Asset Management > Addressables > Event Viewer"

 

## Addressables시스템을 통한 Contents 업데이트

업데이트 크기를 줄이기 위한 workflow

- Addressables은 코드가 아닌 content만 배포가능 

- 코드 변경시에는 새로운 Player build와 Content build가 필요 (e.g. prefab의 monobehaviour컴포넌트가 참조하는 script)

  - Script API 변경없이 내부로직 변경 assembly를 재배포하는 방법은 가능한지 확인필요

 

## 메모리 관리

- 그룹화 및 종속성 관리를 통해 적절한 시점에 관련된 자산들이 효율적으로 메모리를 사용하고, 필요한 시점에 메모리에서 내려가서 메모리 관리가 효율적으로 되도록 구성 필요

- Load시 Release 필요

- Instantiate시 ReleaseInstance필요 : 공식문서

  - instantiationParameters : 다수의 인스턴스화에 동일한 인자값 사용시 해당 구조체를 통해 사용

  - trackHandle : 작업핸들을 Addressables시스템에서 추적할지 여부. true시 `Addressables.ReleaseInstance`를 통해 자산 릴리즈 가능. false시 작업핸들참조를 직접 저장 및 해제

 

## 기타

- 로드시 `WaitForCompletion`은 실행 스레드를 차단하고 동기적으로 대기. Unity 2020.1 이하 버전에서는 상황에 따라 효율적일 수도 있으나 Unity 2020.2 이상에서는 비동기 방식과 성능차이가 미미하기에 사용 지양

- Google PAD(Play Asset Delivery)와 연동하려면 아래 링크를 참조

  - PAD API 공식매뉴얼

  - PAD API 공식문서

  - Addressables-PAD 연동 공식샘플

  - Google 공식 Unity plug-in : 단, Addressables가 아닌 레거시 AssetBundles시스템을 사용함에 유의

- 처음에는 로직 script 부분까지 라이브업데이트가 가능할거라 기대했는데 해당부분 수정은 전체를 재빌드 및 배포해야한다. (포럼공식답변) 라이브 업데이트하는 다른 방법이야 많겠지만 ScriptableObject와 같이 직렬화 자산으로 로직을 구성한다면 Addressables를 통한 라이브 업데이트도 가능할것 같다. 하지만 이경우 해킹에 취약해질것 같다.

- Unity는 API들이 빠르게 변경되고 문서 업데이트가 느린 경우가 많아서 관련 문서나 영상들은 오래될수록 잘못되어 있는 경우가 많다. 항상 최신버전의 공식 문서나 공식 답변이 아닌 경우에는 의심하는것이 좋다.

- 기타 자세한 사용방법은 아래의 링크 참조

 

 

## References

https://docs.unity3d.com/Packages/com.unity.addressables@1.19/manual/index.html

 

Addressables | Addressables | 1.19.19

Addressables The Addressables system provides tools and scripts to organize and package content for your application and an API to load and release assets at runtime. When you make an asset "Addressable," you can use that asset's address to load it from an

docs.unity3d.com

https://docs.unity3d.com/Packages/com.unity.addressables@1.19/api/UnityEngine.AddressableAssets.html

 

Namespace UnityEngine.AddressableAssets | Addressables | 1.19.19

Namespace UnityEngine.AddressableAssets Classes Entry point for Addressable API, this provides a simpler interface than using ResourceManager directly as it assumes string address type. Reference to an asset label. This class can be used in scripts as a fi

docs.unity3d.com

https://blog.unity.com/kr/games/addressable-asset-system

 

어드레서블 에셋 시스템 | Unity Blog

어드레서블의 주된 기능은 로드할 대상이 되는 에셋과 에셋이 로드되는 위치 및 방식을 분리하는 것입니다. 씬, 프리팹, 텍스트 에셋을 비롯한 모든 에셋을 어드레서블(위치 지정 가능)로 표시

blog.unity.com

https://unity.com/how-to/simplify-your-content-management-addressables

 

Simplify your content management with Addressables

Learn how the Addressable Asset System can simplify your content management at both edit and runtime so your game’s initial and updated releases are smoother and easier.

unity.com

https://github.com/Unity-Technologies/Addressables-Sample

 

GitHub - Unity-Technologies/Addressables-Sample: Demo project using Addressables package

Demo project using Addressables package. Contribute to Unity-Technologies/Addressables-Sample development by creating an account on GitHub.

github.com

https://www.youtube.com/watch?v=EP3pvPAcHSo 

https://lunchballer.com/archives/1559

 

[Unity] Addressable과 메모리 관리

Addressable을 이용하고 있다면 메모리 관리 측면에서 잘 사용하고 있는지 체크해 볼 필요가 있다. public IEnumerator Start() { opHandle = Addressables.LoadAssetAsync<GameObject>(key); yield return opHandle; if (opHandle.Status

lunchballer.com

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함