반응형

에셋 번들 중 원하는 번들만 빌드하기


유니티 엔진을 이용한 게임 개발 과정에서 패치 시스템 등을 위한 도구로서 에셋 번들이 자주 사용되는데 번들의 효율적인 관리와 사용을 위해서 모든 에셋들을 한 번들에 묶지 않고, 필요한 분류에 따라서 여러 번들에 나누어서 묶어서 사용하게 된다. 예를 들자면 캐릭터에 사용되는 리소스와 에셋들만 모아서 "character"라는 이름의 번들로 묶거나, UI에 사용되는 이미지들만 모아서 "ui_texture"라는 이름의 번들로 묶는 것이다.


이렇게 분류별로 나누어둔 번들은 다른 포스트에서 언급(http://wergia.tistory.com/29)했듯이 다음과 같이 BuildAssetBundles() 라는 함수를 통해서 빌드할 수 있다. 다음은 그 예시이다.


BuildPipeline.BuildAssetBundles(Application.dataPath + "/AssetBundles", buildAssetBundleOption, buildTarget);


위의 예시를 통해서 묶어둔 에셋들을 번들로 빌드할 수 있는데, 이 코드를 사용할 경우, 당신이 지정한 모든 번들들을 한꺼번에 빌드한다. 이것은 에셋 번들을 테스트로 빌드하거나, 적은 수의 혹은 작은 용량의 번들을 빌드할 때는 인식하지 못했던 문제를 발생시킨다. 이 문제는 개발자가 게임을 개발하는데 투자하는 가장 중요한 자원을 소모시킨다. 그 자원은 바로 "시간"이다.




작은 용량의 에셋을 번들로 빌드할 때는 고작 몇 초의 시간이 걸릴 뿐이지만, 수 GB의 에셋들을 번들로 빌드할 때는 5-10분, 혹은 그보다 많은 시간을 소모하게 된다. 만약에 가장 작은 크기의 번들에 들어가는 에셋을 수정했는데 새로이 번들을 빌드하기 위해 모든 에셋번들을 빌드해야 한다면 얼마나 많은 시간을 무의미하게 소모하게 될 것인가? 필요한 번들만을 빌드했다면 고작 수십 초에서 2-3분의 시간만을 소모했을 작업을 수 분, 수십 분을 소모해야 한다면 이 얼마나 불합리한 일인가?


그렇기 때문에, 필요한 번들만을 빌드하는 방법을 알아두어야만 한다.


AssetBundleManifest BuildPipeline.BuildAssetBundles(

string outputpath, // 빌드된 에셋 번들이 생성될 경로

AssetBundleBuild[] builds, // 빌드할 에셋 번들들의 정보

BuildAssetBundleOption assetBundleOptions, // 에셋 번들 빌드 옵션

BuildTarget targetPlatform // 에셋 번들의 타겟 플랫폼

);


필요한 번들만을 빌드하는 방법으로 유니티에서는 위의 코드와 같은 BuildAssetBundles() 함수의 오버로드를 제공한다. 원래 에셋 번들 빌드에 사용하던 함수에서 AssetBundleBuild라는 구조체 형식의 매개변수가 추가되었는데, 빌드하고자 하는 번들의 정보를 담는 구조체이다. 원하는 에셋 번들을 빌드하기 위해 제공해야할 정보들은 다음과 같다.


public struct AssetBundleBuild
{
    public string assetBundleName;   // 빌드할 에셋 번들의 이름
    public string assetBundleVariant; // 빌드할 에셋 번들의 Variant
    public string[] assetNames;        // 에셋 번들에 포함될 에셋들의 경로와 이름
}


빌드하고자 하는 에셋 번들에 대한 AssetBundleBuild 구조체 혹은 구조체 배열을 만든 뒤, 빌드할 에셋 번들의 이름, Variant(variant가 없다면 넣지 않아도 된다.), 에셋번드레 포함될 에셋들의 경로와 이름을 넣어주고 BuildAssetBundles() 함수의 2번째 매개변수로 전달하고 함수를 실행하게 되면 한 번에 모든 에셋 번들들을 빌드할 필요없이 원하는 에셋 번들만을 빌드할 수 있게 된다.





빌드하고자 하는 에셋 번들에 포함될 에셋들 찾기


원하는 에셋 번들만을 빌드하고자 할 때는 위에서 봤듯이 AssetBundleBuild 구조체를 만들어 필요한 정보들을 채워넣어 주어야 하는데, 그 중에서 에셋 번들에 포함될 에셋들의 경로와 이름인 assetNames의 경우에는 수동으로 입력하는 것은 매우 불편할 뿐더러 프로젝트가 커지면 커질 수록 관리하기도 힘들고 어떤 에셋이 어느 번들에 포함되기로 되어있는지 기억하기도 힘들어질 것이다.


이런 경우를 위해서 유니티에서 제공하는 함수가 있는데 바로 다음의 함수이다.


string[] AssetDatabase.GetAssetPathsFromAssetBundle(

string assetBundleName  // 찾고자 하는 에셋들이 포함된 에셋 번들 이름

);


위의 함수를 사용하면 유니티 에디터의 Inspector 창에서 해당 번들 이름으로 지정해둔 모든 에셋들의 경로와 이름을 string의 배열 형태로 반환한다. 이것을 AssetBundleBuild의 assetNames에 넣어주면 간편하게 번들에 포함될 에셋들의 정보를 AssetBundleBuild 구조체에 넣을 수 있다.


빌드하고자 하는 에셋 번들만을 빌드하는 간단한 예제 함수의 전체는 다음과 같다.


public void BuildNeedAssetBundle(string bundleName)
{
    if (!Directory.Exists(Application.dataPath + "/AssetBundles"))
    {
        Directory.CreateDirectory(Application.dataPath + "/AssetBundles");
    }

    AssetBundleBuild[] buildBundles = new AssetBundleBuild[1];

    buildBundles[0].assetBundleName = bundleName;
    buildBundles[0].assetNames = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName);

    BuildPipeline.BuildAssetBundles(Application.dataPath + "/AssetBundles", buildBundles, buildAssetBundleOption, buildTarget);
}


반응형
  1. ㅇㅇ 2018.05.11 02:50

    좋은 글들 남기어 주셔서, 많은 도움이 되고 있습니다.
    감사합니다.

반응형

Unity3D로 게임 클라이언트를 제작하고 Nettention사의 ProudNet을 이용하여 게임 네트워크를 담당하여 게임을 제작하는 과정에서 안드로이드 빌드로 포팅해서 모바일에서 실행시켰을 때 클라이언트가 서버에 제대로 접속하지 못하는 문제점을 발견했다. 똑같은 클라이언트에 대해서 PC로 포팅 했을때에는 서버에 제대로 접속이 되는데에 반해서 모바일 버전은 접속이 안되는 바람에 하루 가까이 시간을 쏟아서 해결책을 찾았는데 문제의 해결법은 매우 간단했다.

 

해결책

  1. File 메뉴에서 Build Setting을 연다.(혹은 Ctrl + Shift + B 단축키로 열 수 있다.)
  2. Platform 리스트 중에서 Android를 선택하고 그 아래에 있는 Player Setting ... 버튼을 누른다.
  3. 그러면 Inspector 창에 Player Setting이 열리는데 아래쪽에 안드로이드 모양 탭중에서 Other Setting이라는 메뉴를 찾는다.
  4. 그 중에 굵은 글씨로 Configuration 메뉴 중에 Internet Access 라는 항목이 있다.
  5. 이 항목의 기본 값은 Auto로 되어 있는데 이것을 Require로 변경한다.

 


위의 그림처럼 Internet Access 항목을 Require로 변경해주면된다.

 

이상의 과정을 모두 끝내고 난 이후에 다시 안드로이드 버전으로 빌드하여 모바일에 설치하고 실행하면 서버 접속이 원활하게 이루어지는 것을 알 수 있다.

 

이러한 문제가 ProudNet API를 사용할 때만 나타나는 것인지 아니면 다른 네트워크 API를 사용했을때도 나타나는 문제인지는 모르겠지만 인터넷 상에서 이와 관련된 정보를 찾아보기가 쉽지 않아서 개인적으로 참고도 할 겸, 다른 사람이 찾아봐서 도움도 될 겸해서 포스팅을 남겨둔다.


반응형
  1. 2018.09.05 21:05

    비밀댓글입니다

    • wergia 2018.09.06 10:33 신고

      음 프라우드넷으로 네트워크 구현했을 때, 안드로이드가 서버에 접속못하는 문제는 internet access require가 제일 중요했었는데 그걸 설정했는데도 안된다는 말씀이시군요.

      혹시 Internet Access 설정의 5줄 위에 있는 Api Compatibility Level은 어떤 것으로 설정되어 있나요? 프라우드넷으로 작업하던 당시에 .NET 2.0 Subset이 아니면 안되었던 이유가 있었던 것 같은데 이 쪽도 연관이 있을 수 있다고 봅니다.

반응형

효과적으로 Debug를 하기 위해서는 Debug 빌드를 유지해야한다.


하지만 사람들은 Debug 빌드를 잘 사용하지 않는데 그것은 Debug 빌드의 속도가 Release 빌드에 비해서 컴파일 시간도 실행 시간도 느리기 때문이다.


Debug 빌드는 기본적으로 최적화 기능이 꺼져있기도 하고, 프로그래머가 에러를 찾기위해 온갖 assert를 넣고 하다보면 프로그램이 더욱 느려지기 마련이다.


하지만 Release 빌드는 속도가 빠른 반면에 에러를 잡기위한 디버깅이 힘들어진다. 최적화 단계에 들어선 이후에는 성능이 매우 중요하겠지만 그 이전 단계에서는 프로그램이 얼마나 올바르게 동작하는 가가 제일 중요하다. 그렇기 때문에 버그를 빠르게 찾아내고 수정하기 위해서는 반드시 Debug 빌드를 언제나 컴파일되고 실행되게 유지해야한다.


만약 Debug 빌드가 컴파일되지 않게 망가뜨린 프로그래머가 있다면 그는 반드시 다른 프로그래머가 언제든지 Debug 빌드를 실행시킬 수 있도록 복구시켜 두어야 한다.


Debug 빌드를 사람들이 잘 쓰지 않는 이유는 속도가 느리기 때문인데 속도를 빠르게 하기 위해 무조건 Release 빌드는 쓰는 것이 아니라 어떻게 해서든 Debug 빌드를 빠르게 만들어야 한다.


Debug 기능을 쓸 수 있지만 어느 정도 최적화 기능을 켠 Fast Debug 빌드를 만든다던가. 각 부서별로 자기 부서에 필요한 부분만 Debug로 돌리고 나머지는 Release로 돌릴 수 있게 자동화를 한다던가. 여기저기 있는 assert를 효과적으로 제거한다던가하는 방식으로 말이다.


참고 ::



반응형
반응형

Direct3D는 어떻게 보면 두 개의 레이어가 따로 있다. C++ 쪽에서 Debug를 돌려도 렌더링 쪽에서는 느려질 수 있는 것은 그렇게 많지 않다.


Direct3D에서는 실제 GPU로 들어가는 부분에 Direct3D Runtime이 있다. 여기에도 Debug 빌드와 Release 빌드가 있는데 이것은 C++ 코드와 전혀 상관없이 DirectX Control Panel에 들어가서 수정할 수 있는 것이다. 그것을 Release로 만들면 최적화가 적용되어서 빨라지고 Debug로 만들면 최적화 기능이 꺼지고 Debug 기능들로 인해서 느려진다.


일반적으로 대부분의 프로그래머는 빠르고 에러도 덜 뱉는다는 이유로 Direct3D를 Release로 켜놓고 사용하는데 어느 순간엔가는 이것을 Debug 빌드로 돌려서 Debug를 해야하는 순간이 온다. Memory leak 문제가 발생할 수도 있고, 참조 카운터 문제가 있을 수도 있다. 그래서 이것을 Debug로 바꾸는 순간 엄청난 Warning과 Error를 발생시키는 경우가 있다. 매 프레임마다 같은 혹은 비슷한 장면은 계속해서 그려야하는 렌더링의 특징 상 break를 걸기도 어렵고 Debugging도 어려워진다.


그렇기 때문에 그래픽 프로그래머는 반드시 Direct3D Runtime을 Debug 빌드로 두고 작업을 해야한다. Release 빌드에선 에러나 경고를 뱉지 않던 코드가 Debug 빌드에서 쏟아져 나올 수 있다. 그런 것을 무시하고 Release 빌드로만 작업하고 그런 에러와 경고가 쌓인 상태로 나중에 다른 프로그래머가 Debug를 하려고 하면 수많은 경고와 에러로 인해서 도저히 Debug 작업을 할 수 없게 된다. 결국 작업을 하기 위해서는 이 수많은 에러와 경고들을 처리할 수 밖에 없는데 이렇게 수 개월치 쌓인 문제를 한꺼번에 처리하는 것보다는 에러 하나, 경고 하나가 발생했을때 바로 처리하는 것이 훨씬 깔끔하고 빠른 문제 처리 방법이다.


렌더링 쪽에서는 크게 Debug 빌드가 느린 것 같지는 않은데 게임 쪽에서는 프레임 속도가 제대로 안나오면 문제가 있을 수도 있다.


참고 :: https://www.youtube.com/watch?v=eOF6IZU4nxQ


반응형

+ Recent posts