Version: Unity 6.0 (6000.0)
언어 : 한국어
AssetBundle file format reference
에셋 번들 종속성

에셋 번들의 전문적인 활용

에셋 번들을 로드하는 데 사용할 수 있는 두 가지 API가 있습니다.

AssetBundle.LoadFromFile

AssetBundle.LoadFromFile

이 API는 로컬 스토리지에서 압축되지 않은 번들과 청크 압축된 번들(LZ4)을 로드할 때 매우 효율적입니다. 파일 콘텐츠를 디스크에서 직접 증분식으로 읽을 수 있기 때문입니다. 이 메서드를 사용하여 전체 파일 압축(LZMA)으로 압축된 파일을 로드하는 것은 파일이 먼저 메모리에 완전히 압축 해제되어야 하므로 효율성이 떨어집니다.

LoadFromFile 사용 방법의 예시:

using System.IO;
using UnityEngine;

public class LoadFromFileExample : MonoBehaviour
{
    void Start()
    {
        var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));

        if (myLoadedAssetBundle == null)
        {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
        Instantiate(prefab);
    }
}

로드 프로세스 중에 앱을 차단하는 대신 비동기 버전인 AssetBundle.LoadFromFileAsync도 사용할 수 있습니다.

에셋 번들이 실제로 로컬 파일에 저장되지 않은 경우 에셋 번들을 로드하는 데 사용할 수 있는 다른 여러 가지 방법이 있습니다. 예를 들어 AssetBundle.LoadFromMemoryAsync를 사용할 수 있습니다.

UnityWebRequestAssetBundle

UnityWebRequestAssetBundle은 API를 호출하여 에셋 번들을 다운로드, 캐싱 및 로드하기 위한 특수 웹 요청을 생성할 수 있습니다.

일반적으로 URL은 웹 서비스에서 공개된 파일을 가리키는 ‘https://’ 주소입니다. 직접 파일 시스템 액세스를 지원하지 않는 플랫폼의 로컬 데이터에 액세스하는 경우 ’file://’일 수도 있습니다.

이 요청은 로드된 에셋 번들의 에셋 번들 오브젝트를 가져오기 위해 DownloadHandlerAssetBundle.GetContent(UnityWebRequestAssetBundle)에 전달될 수 있습니다.

예:

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class DownloadExample : MonoBehaviour
{
    IEnumerator Start()
    {
        string uri = "https://myserver/myBundles/bundle123";
        uint crc = 1098980; // Expected content CRC

        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, crc);
        yield return request.SendWebRequest();

        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
        yield return loadAsset;

        Instantiate(loadAsset.asset);
    }
}

또는 Await 지원 시 2023.1부터 시작:

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class DownloadExample : MonoBehaviour
{
    async void Start()
    {
        string uri = "https://myserver/myBundles/bundle123";
        uint crc = 1098980; // Expected content CRC

        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, crc);
        await request.SendWebRequest();

        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
        await loadAsset;

        Instantiate(loadAsset.asset);
    }
}

단순성을 위해 예제는 코드에 하드코딩된 CRC 값을 보여 줍니다. 그러나 실제로 에셋 번들에 대한 예상 CRC 값은 에셋 번들을 다운로드하기 전에 별도로 다운로드되거나 파일에서 검색됩니다. 에셋 번들 다운로드 무결성 및 보안을 참조하십시오.

참고: 이 코드가 호출될 때마다 전체 에셋 번들 콘텐츠를 다운로드하지 않도록 하려면 에셋 번들에 대한 캐싱을 활성화하면 됩니다. 이는 UnityWebRequestAssetBundle.GetAssetBundle을 호출할 때 에셋 번들 해시를 전달하여 수행합니다. 해시는 에셋 번들 매니페스트에서 사용할 수 있으며, 이 매니페스트에 대해서는 이 섹션의 후반부에서 설명합니다. 해시는 사용자가 요청하는 에셋 번들의 정확한 빌드에 대한 버전 식별자 역할을 합니다. 캐시와 압축에 대한 관련 고려 사항은 에셋 번들 압축 및 캐싱에서 자세히 알아보십시오.

에셋 번들(AssetBundles)에서 에셋(Asset) 로드

이제 에셋 번들을 성공적으로 다운로드했으므로 여러 에셋을 로드할 수 있습니다.

일반 코드 스니핏:

T objectFromBundle = bundleObject.LoadAsset<T>(assetName);

T는 로드하려는 에셋 유형입니다.

에셋을 로드하는 방법을 결정할 때 몇 가지 옵션이 있습니다. LoadAsset, LoadAllAssets가 있고, 각각의 비동기 버전인 LoadAssetAsyncLoadAllAssetsAsync가 있습니다.

에셋 번들에서 에셋을 동기식으로 로드하는 방법은 다음과 같습니다.

단일 에셋(예: 프리팹의 루트 게임 오브젝트)을 로드하려면 다음 단계를 따르십시오.

GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);

모든 에셋을 로드하려면 다음을 사용합니다.

Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();

이는 각 에셋의 모든 루트 오브젝트가 포함된 배열을 반환합니다.

이전에 표시된 메서드는 로드하는 오브젝트 유형 또는 오브젝트 배열을 반환하는 반면 비동기 메서드는 AssetBundleRequest를 반환합니다. 에셋에 액세스하기 전에 이 작업이 완료될 때까지 기다려야 합니다. 에셋을 비동기식으로 로드하려면 다음을 사용합니다.

AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request; // or await request;
var loadedAsset = request.asset;

또는

AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request; // or await request;
var loadedAssets = request.allAssets;

에셋을 로드했으면 시작할 수 있습니다. Unity의 모든 오브젝트처럼 로드된 오브젝트를 사용할 수 있습니다.

에셋 번들 매니페스트(AssetBundle Manifests) 로드

에셋 번들 매니페스트를 로드하는 작업은 매우 유용할 수 있습니다. 특히 에셋 번들 종속성을 처리할 경우 더욱 그렇습니다.

유용한 AssetBundleManifest 오브젝트를 얻으려면 해당 추가 에셋 번들(들어가 있는 폴더와 이름이 같은 에셋 번들)을 로드하고 이 에셋 번들에서 유형이 AssetBundleManifest인 오브젝트를 로드해야 합니다.

매니페스트 자체를 로드하는 방법은 다른 에셋을 에셋 번들에서 로드하는 방법과 똑같습니다.

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

이제 위 예제의 매니페스트 오브젝트를 통해 AssetBundleManifest API 호출에 액세스할 수 있습니다. 여기에서 매니페스트를 사용하여 빌드한 에셋 번들에 대한 정보를 가져올 수 있습니다. 이 정보에는 에셋 번들에 대한 종속성 데이터, 해시 데이터, 배리언트 데이터가 포함됩니다.

이전의 에셋 번들 종속성 섹션에서는 에셋 번들에서 에셋을 로드하기 위해 에셋 번들이 종속된 에셋 번들을 먼저 로드하는 방법에 대해 설명했습니다. 매니페스트 오브젝트를 사용하면 종속성을 동적으로 찾고 로드할 수 있으므로 코드에서 모든 에셋 번들 이름과 그 관계를 명시적으로 하드코딩할 필요가 없습니다. ‘assetBundle’이라는 이름의 에셋 번들에 대한 모든 종속성을 로드한다고 가정해 보겠습니다.

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundle you want the dependencies for.
foreach(string dependency in dependencies)
{
    AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}

이제 에셋 번들 또는 에셋 번들 종속성과 에셋을 로드하려고 하므로, 이렇게 로드된 에셋 번들을 모두 관리하는 방법에 대해 설명하겠습니다.

##로드된 에셋 번들 관리

참고: Addressables 패키지는 에셋 번들, 종속성 및 에셋 로드를 관리하기 위한 기존 시스템을 제공합니다. Unity는 에셋 번들을 직접 관리하는 대신 Addressables를 사용할 것을 권장합니다.

참고 항목: Unity Learn 튜토리얼 로드된 에셋 번들 관리

Unity는 활성 씬에서 오브젝트가 제거되어도 해당 오브젝트를 자동으로 언로드하지 않습니다. 에셋 클린업은 특정 시점에 트리거되며 수동으로 트리거할 수도 있습니다.

에셋 번들을 로드하고 언로드할 시점을 파악하는 것이 중요합니다. 에셋 번들을 잘못 언로드하면 메모리에 오브젝트가 중복되거나 누락될 수 있습니다.

에셋 번들 관리에 대해 알아야 할 가장 중요한 점은 AssetBundle.Unload(bool) 또는 AssetBundle.UnloadAsync(bool)을 호출하는 시기와 함수 호출에 true 또는 false를 전달해야 하는지 여부입니다. Unload는 메모리에서 에셋 번들 헤더와 기타 데이터 구조체를 제거하여 에셋 번들을 언로드하는 비정적 함수입니다. 인자는 이 에셋 번들에서 인스턴스화된 모든 오브젝트를 언로드할지 여부를 나타냅니다.

AssetBundle.Unload(true)는 에셋 번들에서 로드된 모든 게임 오브젝트(및 종속성)를 언로드합니다. 복사한 데이터가 에셋 번들에 속하지 않기 때문에 씬에 복사한 오브젝트(예: Instantiate 호출)는 포함되지 않습니다. 씬의 오브젝트가 에셋 번들에서 로드된 텍스처를 참조하고 여전히 에셋 번들에 속한 경우 이 호출을 통해 텍스처가 사라지고 Unity는 해당 텍스처를 누락된 텍스처로 취급합니다.

아래 그림과 같이 머티리얼 M이 에셋 번들 AB에서 로드되어 프리팹 P에서 사용된다고 가정해 보겠습니다.

AB.Unload(true)가 호출될 경우 활성 씬에 있는 오브젝트에서 참조되는 M의 모든 인스턴스도 파괴됩니다.

대신 AB.Unload(false)를 호출했다면 M의 인스턴스가 메모리에 남아 있습니다. 이는 원래 에셋 번들에 다시 연결되지 않으며 독립적인 오브젝트가 됩니다.

나중에 AB가 다시 로드되면 Unity는 M의 기존 복사본을 에셋 번들의 머티리얼에 다시 연결하지 않습니다.

프리팹 P의 다른 인스턴스를 생성한 경우 M의 기존 복사본을 사용하지 않으며, 대신 M의 두 번째 복사본이 로드됩니다.

일반적으로 AssetBundle.Unload(false)를 사용하면 오브젝트 중복 및 기타 문제로 이어질 수 있습니다. 대부분의 프로젝트에서는 이 문제를 피하기 위해 AssetBundle.Unload(true)를 사용해야 합니다. 안전하게 AssetBundle.Unload(true)를 호출하려면 두 가지 일반적인 전략이 있습니다.

  • 애플리케이션 수명 중에 임시 에셋 번들이 언로드되는 시점(예: 레벨 간 또는 화면 로딩 중)을 분명히 정의하는 방법

  • 개별 오브젝트에 대한 레퍼런스 카운트를 유지하고 모든 구성 오브젝트가 사용되지 않은 경우에만 에셋 번들을 언로드하는 방법. 이를 통해 애플리케이션은 메모리 중복 없이 개별 오브젝트를 언로드 및 다시 로드할 수 있습니다.

애플리케이션이 AssetBundle.Unload(false)를 사용해야 하는 경우 개별 오브젝트를 다음 두 가지 방법으로만 언로드할 수 있습니다.

  • 원치 않는 오브젝트에 대한 모든 레퍼런스를 제거합니다. 예를 들어 로드된 다른 오브젝트에 해당 오브젝트를 가리키는 필드가 없어야 합니다. 이 작업이 완료되면 Resources.UnloadUnusedAssets를 호출합니다.

  • 씬을 비가산적으로 로드합니다. 그러면 현재 씬의 모든 오브젝트가 파괴되고 Resources.UnloadUnusedAssets가 자동으로 호출됩니다.

AssetBundle file format reference
에셋 번들 종속성