Unity 검색

어드레서블 에셋 시스템의 새로운 기능 소개

2021년 4월 14일 테크놀로지 | 7 분 소요
Books in library
Books in library

어드레서블 에셋 시스템을 활용하여 복잡한 Unity 프로젝트의 콘텐츠를 안전하고 효율적으로 관리할 수 있습니다. 동기식 어드레서블 API를 통해 훨씬 간편하게 프로젝트에 어드레서블 시스템을 사용하는 방법을 알아보세요.

어드레서블 에셋 시스템(줄여서 ‘어드레서블’)은 에셋과 메모리의 효율적 관리가 필요한 프로젝트에 권장되는 툴입니다. 어드레서블은 에셋 레퍼런싱과 패키징 문제를 분리하여 플레이모드와 배포된 플레이어 빌드 모두에서 반복 작업 속도를 높이며 자동 메모리 관리와 프로파일링 툴을 제공합니다. 이 시스템은 런타임 시 로딩과 콘텐츠 배포를 위해 에셋을 패키징하는 데 사용되는 Unity의 전용 파일 구조인 에셋 번들에 에셋을 빌드합니다. 그런 다음 콘텐츠 카탈로그를 빌드하여 더 유연하게 런타임 시 종속성을 트래킹하고 로딩을 관리할 수 있도록 만들어 줍니다.

Unity 에셋 번들에서 에셋을 로딩하면 더 이상 필요하지 않은 콘텐츠를 메모리에서 효율적으로 언로딩할 수 있습니다. 어드레서블을 통해 로드하면 로딩된 에셋과 종속성의 참조 횟수가 자동 계산되며 더 이상 사용되지 않는 번들과 관련 에셋이 자동으로 언로딩됩니다. 또한 어드레서블은 에셋 번들 레퍼런스 카운트 및 로딩된 에셋의 실시간 디버깅을 위한 시각적 프로파일러를 제공합니다. 즉 어드레서블 에셋 시스템을 이용하면 게임 에셋을 저장하고 분류하여 빠르게 찾고 로딩할 수 있습니다. 에셋을 호스팅하여 라이브 게임에 전송할 준비가 되었으면 Cloud Content Delivery를 살펴보세요. 이 솔루션을 이용하면 기존 코드를 변경할 필요없이 유니티의 콘텐츠 전송 네트워크(Content Delivery Network, CDN) 파트너사인 Akamai를 통해 에셋을 플레이어에게 직접 제공할 수 있습니다. 어드레서블과 CDN을 이용하면 빌드를 크게 간소화할 수 있으며 게임이 업데이트될 때마다 플레이어가 새 게임 버전 전체를 다운로드하고 설치할 필요가 없습니다.

어드레서블 에셋 시스템은 패키지 관리자에서 바로 설치할 수 있으며, Unity 2019 LTS 이상 버전에서 지원됩니다. 시작에 도움이 되는 가이드를 보려면 어드레서블 에셋 시스템 기술 자료를 확인하시기 바랍니다. 여기에서 어드레서블을 통해 메모리를 절감하는 방법을 살펴볼 수 있습니다. 포스팅은 프로페셔널 서비스 팀과 함께 고객 프로젝트 최적화를 수행한 패트릭 드바니의 경험을 기반으로 작성되었습니다.

기존의 비동기 동작

거의 모든 어드레서블 API는 비동기식이며, 사용자가 작업을 진행하여 연산이 완료되면 결과를 가져올 수 있도록 하는 핸들을 반환합니다. 이 핸들은 AsyncOperationHandle입니다.

처음에는 전체가 비동기식인 이 워크플로를 중심으로 어드레서블을 설계했으며, 당시에는 CDN 지원이 필요했던 모바일 고객에 집중하고 있었습니다. 덕분에 콘텐츠가 어디에 저장되어 있더라도 상시 작동하는 안전한 API를 제공할 수 있었습니다. 예를 들어 현재 로컬이거나 처음에는 로컬에 저장되어 있던 대상을 로딩할 때, 실제로는 원격 호스팅된 종속성이 해당 대상에 포함된 경우가 있습니다. 이 항목을 비동기적으로 로딩하면 다른 예기치 않은 다운로드까지 모두 처리할 수 있게 됩니다.

위와 같은 비동기 제한은 이 프로파일에 적합하지 않은 프로젝트에 아직 최적화되지 않았습니다. 대부분의 사용자는 원격 콘텐츠가 없거나 다운로드 관리가 매우 세밀하게 제어되는 게임을 개발합니다. 고객층이 계속 확대되고 다양해짐에 따라 유니티는 동기식 API의 필요성을 인지하게 되었습니다.

동기식 어드레서블 API

이러한 이유로 동기식 어드레서블 API를 추가했습니다. 이 API는 어드레서블 패키지 1.17.4 버전으로 제공되며 Unity 2021.1, Unity 2020 LTS, Unity 2019 LTS와 호환됩니다.

이 API가 추가된 덕분에 이제 프로젝트에서 어드레서블을 사용하기 위해 에셋 로딩을 비동기식으로 만들 필요가 없습니다. 새로운 동기식 기능은 AsyncOperationHandle의 WaitForCompletion이라는 메서드 형태로 제공되며 해당 연산의 결과를 반환합니다.

앞서 설명드린 대로 기존의 어드레서블 API는 거의 모두 비동기식이며 모든 비동기식 API는 이 핸들을 반환합니다. 핸들 클래스에 WaitForCompletion 메서드를 포함하여 기존의 API가 즉시 동기식으로 변환될 수 있도록 만들었습니다. 

예를 들어 예전에는 Addressables.LoadAssetAsync(“MyPrefab”)를 호출하면 GameObject 연산의 핸들인 AsyncOperationHandle가 반환되었습니다. 이 핸들로 WaitForCompletion을 호출하면 로딩이 완료될 때까지 현재 실행 중인 코드가 차단됩니다. 로딩이 완료되면 WaitForCompletion은 요청된 GameObject를 반환합니다.

비동기식이든 동기식이든 마지막에는 모든 연산을 릴리스합니다. 연산 자체를 릴리스하거나, 결과로 전달하여 결과 내에서 연산을 찾아볼 수도 있습니다.

성능 측면

대부분의 경우 동기식 로딩과 비동기식 로딩의 성능은 서로 비슷합니다. 하지만 때에 따라 속도가 약간 더 빠르거나 느려질 수 있으며 일부 특별한 경우에는 상당히 느려질 수도 있습니다.

속도가 현저히 느려지는 첫 번째 경우는 Addressables 상호작용에 의해 다수의 엔진 호출이 이루어지는 때입니다. 다수의 에셋을 동시에 로딩하거나, 크고 복잡한 종속성 트리를 가진 소수의 에셋을 로딩할 때 이 현상이 일어나기 쉽습니다. Unity 2021.1 버전에서 비동기식 엔진 인터페이스를 동기식으로 실행하면 호출당 지연이 발생하기 때문입니다. Unity 2021.2에서는 이러한 지연이 사라질 것이며, 이 릴리스는 현재 알파 버전으로 제공되고 있습니다. 

성능이 현저히 저하될 수 있는 두 번째 경우는 다수의 대규모 연산이 백그라운드에서 실행되는 상황에서 작은 연산이 WaitForCompletion을 호출할 때입니다. 그러면 단일 연산의 WaitForCompletion이 엔진에서 비동기 로드 연산 대기열을 차단하게 됩니다. 대기열 앞쪽에 대규모 연산이 있는 경우 실행 대기 중인 연산이 완료되어 값을 반환하기 전에 대규모 연산이 먼저 끝나버릴 수도 있습니다.

향후 전망

오래 전부터 동기식 인터페이스가 필요할 것이라 예상했습니다. 기존 시스템에 강력하고도 안정적인 API를 빌드하기 위해 예상보다 많은 시간이 걸렸지만, 드디어 기쁜 마음으로 개선 사항을 공유할 수 있게 되었습니다.

시간과 노력을 많이 투자한 만큼 어드레서블 에셋 시스템이 사용자의 프로젝트 콘텐츠 관리 전략에 정확히 부합했으면 하는 바람입니다. 유니티는 사용자의 피드백을 항상 경청하고 있으며, 제품 개발에 피드백을 반영하고자 최선을 다하고 있습니다. WaitForCompletion에 관한 의견을 댓글로 남기거나 어드레서블 포럼에 작성해 주세요.

제품 개발에 관한 최신 소식은 Unity Pipeline & Integrations 로드맵의 RUNTIME ASSET MANAGEMENT 탭에서 확인하실 수 있습니다. 어드레서블에 관한 아이디어가 있다면 이 페이지 하단에서 신청해주세요.

2021년 4월 14일 테크놀로지 | 7 분 소요