AssetBundle

2021. 7. 26. 12:36unity

에셋번들 (AssetBundles)

에셋 번들은 Unity에서 원하는 에셋을 포함하여 익스포트할 수 있는 파일입니다. 이러한 파일은 전용 압축 포맷을 사용하여 플레이어에서 필요로 할 때 로드 할 수 있습니다. 이는 콘텐츠, 예를 들면, 모델, 텍스처, 오디오 클립 또는 사용되는 씬에서 분리하여 씬 전체를 스트리밍할 수 있습니다.

https://docs.unity3d.com/kr/530/Manual/AssetBundlesIntro.html

 

유니티 - 매뉴얼: 에셋번들 (AssetBundles)

로우 레벨 네이티브 플러그인 인터페이스(Low-level Native Plugin Interface) 4.x버전에서의 에셋번들 빌드 에셋번들 (AssetBundles) 에셋 번들은 Unity에서 원하는 에셋을 포함하여 익스포트할 수 있는 파일입

docs.unity3d.com

서버는 CDN 서버

에셋 번들을 만들 땐 로컬에서 테스트 할 수 있는 버전, CDN에서 테스트할 수 있는 버전 두 개를 만든다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAssetBundles() 
    {
        string path = "Asset/Build AssetBundles";
        if (!Directory.Exists(path)) 
        {
            Directory.CreateDirectory(path);        
        }

 


 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAssetBundles() 
    {
        string path = "Assets/Build AssetBundles";
        if (!Directory.Exists(path)) 
        {
            Directory.CreateDirectory(path);        
        }
        BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.Android);
    }
}

bundle, bundle.manifest 파일이 생성된 것을 확인할 수 있다

bundle : 에셋번들 파일
bundle.manifest : 포함된 에셋, 종속성, 기타 정보를 나타내는 파일

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class App : MonoBehaviour
{

    void Start()
    {
        StartCoroutine
        (
            AssetManager.instance.LoadFromMemoryAsync("Assets/Build AssetBundles/characters", (bundle) =>
            {
                Debug.LogFormat("bundle: {0}", bundle);
                var prefab = bundle.LoadAsset<GameObject>("ch_01_01");
                var model = Instantiate<GameObject>(prefab);
            })
        );
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class AssetManager : MonoBehaviour
{
    public static AssetManager instance;
    
    private void Awake() 
    {
        AssetManager.instance = this;   
    }

    public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback) 
    {
        //파일을 바이트 배열로 읽어서 비동기 방식으로 로드한다.
        byte[] binary = File.ReadAllBytes(path);
        AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
        yield return req;

        callback(req.assetBundle);
    }
}

해당 캐릭터의 프리팹이 잘 생성되었다.

 


AssetBundle Browser 사용해보기

https://github.com/Unity-Technologies/AssetBundles-Browser.git

 

GitHub - Unity-Technologies/AssetBundles-Browser: Editor tool for viewing and debugging asset bundle contents before and after b

Editor tool for viewing and debugging asset bundle contents before and after builds - GitHub - Unity-Technologies/AssetBundles-Browser: Editor tool for viewing and debugging asset bundle contents b...

github.com

 


서버로부터 어셋번들 로드하기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class App : MonoBehaviour
{

    void Start()
    {
        StartCoroutine
        (
            //AssetManager.instance.LoadFromMemoryAsync("Assets/Build AssetBundles/characters", (bundle) =>
            //{
            //Debug.LogFormat("bundle: {0}", bundle);
            //var prefab = bundle.LoadAsset<GameObject>("ch_01_01");
            //var model = Instantiate<GameObject>(prefab);
            //})

            AssetManager.instance.LoadFromServer("ftp://서버주소/AssetBundles/characters")
        );
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.Networking;

public class AssetManager : MonoBehaviour
{
    public static AssetManager instance;
    
    private void Awake() 
    {
        AssetManager.instance = this;   
    }

    public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback) 
    {
        //파일을 바이트 배열로 읽어서 비동기 방식으로 로드한다.
        byte[] binary = File.ReadAllBytes(path);
        AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
        yield return req;

        callback(req.assetBundle);
    }

    
    public IEnumerator LoadFromServer(string uri) 
    {
        UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(uri);
        yield return req.SendWebRequest();

        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(req);
        Debug.Log(bundle);
    }
}

 


서버로부터 어셋번들 로드해서 로컬에 저장

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.IO;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;

public class AssetManager : MonoBehaviour
{
    public static AssetManager instance;

    private void Awake()
    {
        AssetManager.instance = this;
    }

    public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback)
    {
        //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
        byte[] binary = File.ReadAllBytes(path);
        Debug.Log(binary.Length);
        AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
        yield return req;
        callback(req.assetBundle);
    }

    public IEnumerator LoadFromServer(string path, string fileName)
    {
        string bundleUri = string.Format("{0}/{1}", path, fileName);
        UnityWebRequest req1 = UnityWebRequest.Get(bundleUri);
        yield return req1.SendWebRequest();
        var bytes = req1.downloadHandler.data;
        Debug.Log(bytes.Length);

        var manifestUri = string.Format("{0}.manifest", bundleUri);
        UnityWebRequest req2 = UnityWebRequest.Get(manifestUri);
        yield return req2.SendWebRequest();
        var manifest = Encoding.UTF8.GetString(req2.downloadHandler.data);

        //저장 
        string bundlePath = string.Format("{0}/{1}", Application.persistentDataPath, fileName);
        Debug.Log(bundlePath);
        File.WriteAllBytes(bundlePath, bytes);

        string manifestPath = string.Format("{0}.manifest", bundlePath);
        File.WriteAllBytes(manifestPath, bytes);
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class App : MonoBehaviour
{

    void Start()
    {
        StartCoroutine
        (

            AssetManager.instance.LoadFromServer("ftp://서버 주소/AssetBundles", "characters")
        ); 
        
    }
}

 


로컬에서 어셋번들 불러오기

public IEnumerator LoadFromFileAsync(string path, string fileName, System.Action callback) 
    {
        var req = AssetBundle.LoadFromFileAsync(string.Format("{0}/{1}",path, fileName));
        yield return req;
        var bundle = req.assetBundle;
        Debug.LogFormat("bundle: {0}", bundle);
        dicBundles.Add(fileName, bundle);
        callback();
    }

    public GameObject LoadAsset(string bundleName, string prefabName) 
    {
        return this.dicBundles[bundleName].LoadAsset<GameObject>(prefabName);
    }
    
    public void UnLoadBundle(string bundleName) 
    {
        this.dicBundles[bundleName].Unload(true);
    }
StartCoroutine
        (

            AssetManager.instance.LoadFromFileAsync(Application.persistentDataPath, "characters",()=> 
            {
                var prefab = AssetManager.instance.LoadAsset("characters", "ch_01_01");
                var go = Instantiate<GameObject>(prefab);
            })
            
        );

번들을 딕셔너리에 넣어서 해당 key 값으로 캐릭터 프리팹을 불러온다.

그리고 버튼을 누르면 불러온 어셋번들을 unload 하게 함