Unity 검색

Document management system concept | A business person views a folder and document icons, attempting to search or manage files using an online document database software. (credit: Thapana_Studio - stock.adobe.com)
Document management system concept | A business person views a folder and document icons, attempting to search or manage files using an online document database software. (credit: Thapana_Studio - stock.adobe.com)
공유

Is this article helpful for you?

Thank you for your feedback!

고객 성공 팀의 컨설턴트로 일하며 “에셋 번들을 올바르게 구성한 걸까요?” 같은 질문을 받을 때가 많습니다. 그럴 때마다 저는 항상 이렇게 답합니다. 프로젝트에 따라 다르다고요. 그런 다음 고객과 구체적인 사항에 대해 이야기를 나눕니다. 정확한 답변이긴 하지만 향후 프로젝트에 도움이 되는 인사이트를 제공하지 못하니까요.

흔히 받는 질문인데다 유니티에서 제공하는 어드레서블 가이드라인 및 베스트 프랙티스가 있음에도 이 질문에 대한 더 보편적인 답을 찾기는 쉽지 않았습니다. 일부 사용자들은 작업을 시작할 때 번들이 올바르게 구성되었는지 모르는 경우도 있고, 저는 메모리 최적화를 중심으로 프로젝트를 검토하느라 바빠 프로젝트에 포함된 모든 에셋의 용도를 파악할 수 없기 때문입니다. 게다가 프로젝트 규모가 커질수록 보편적인 가이드라인이 없으면 한 사람이 프로젝트의 모든 에셋을 대상으로 이 질문에 답하는 것은 불가능해집니다.

결국 저는 한 가지를 깨달았습니다. 에셋 번들을 올바르게 구성하는 것으로 관점을 제한하면 보편적인 답을 찾을 수 없게 된다는 거죠. 자세히 설명해 드리겠습니다.

에셋 번들은 로드될 때 메모리를 차지하므로 동시에 로드 및 언로드되는 에셋끼리 번들링하지 않으면 메모리가 최적화되지 않는다는 것입니다. 따라서 에셋이 올바른 번들에 들어 있는지 또는 번들에 올바른 에셋이 들어 있는지 질문하는 것은 올바른 에셋을 제때 로드하고 있는지 질문하는 것과 같습니다. 특정 에셋의 올바른 로드 시점은 에셋의 용도에 좌우되기 때문에 일반적으로 “프로젝트에 따라 다릅니다”라고 답할 수밖에 없는 것입니다. 실제로도 에셋의 용도를 파악하면 에셋이 어떻게 메모리에 로드되는지와 에셋을 어떻게 번들링해야 하는지를 알 수 있습니다.

따라서 핵심은 바로 ‘용도’입니다. 에셋의 용도를 누가 알고 있나요? 그 용도를 모두에게 어떻게 공유할까요? 그리고 언제 공유해야 할까요?

제 생각에 이 질문에 대한 답이 명확해지는 시점은 바로 에셋을 만들 때와 수정할 때입니다. 캐릭터의 특정 텍스처든, 전역 조명 셰이더든, 여러 게임 레벨에 사용할 나무 메시든, 에셋을 만든 사람은 그 용도를 알고 있으므로 이를 전달하기에도 가장 적합한 인물입니다. 아티스트는 일관적인 파일 명명 규칙을 적용하고 용도가 동일한 파일을 하나의 폴더에 정리하면 해당 에셋의 용도를 다른 이들에게 전달할 수 있습니다.

그러면 프로그래머와 다른 팀원들은 이 정보를 바탕으로 동시에 로드되는 여러 에셋을 번들링할 시기와 여부를 결정할 수 있습니다. 따라서 에셋의 용도는 프로젝트를 진행하는 동안 한눈에 파악할 수 있도록 명확하게 제시되어야 하며, 파일 디렉토리는 모든 팀원이 신뢰할 수 있는 SSOT(single source of truth)로 기능해야 합니다.

이 블로그 게시물에서는 향후 프로젝트를 더 효과적으로 구성하는 데 도움이 되는 몇 가지 베스트 프랙티스와 일반적인 에지 케이스를 살펴보겠습니다. 그 전에 일반적인 폴더 구조와 그 문제점을 짚어 보겠습니다.

폴더 구조

제 경험상 폴더 구조는 무작위, 에셋 유형별, 기능별, 용도별의 네 가지 유형으로 분류할 수 있습니다. 이 중에서는 의도를 전달하여 최적의 번들링 전략에 가장 적합한 마지막 구조가 제일 이상적인 유형입니다.

무작위는 흔히 볼 수 있는 구조는 아닙니다. 대부분 소프트웨어 개발에 익숙하지 않은 1인 개발자가 이런 구조를 사용하며, 프로젝트의 규모나 복잡도가 커짐에 따라 자연스럽게 다른 구조로 대체됩니다. 구조가 없거나 무작위인 경우 에셋을 찾기 힘들고 용도를 이해하기가 사실상 불가능하다는 등의 다양한 문제가 수반됩니다.

에셋 유형별 구조는 흔히 볼 수 있는 유형입니다. 많은 아티스트가 에셋을 엔진에 임포트하기 전에 유형별로 분류하기 때문입니다. 에셋 유형을 알고 있다면 그 위치도 쉽게 찾을 수 있지만 그 외의 정보는 모두 알기 어려워집니다. 좋은 명명 규칙을 사용하더라도 캐릭터, 환경, UI 또는 이 세 가지를 조합한 에셋이 특정 셰이더, 텍스처, 메시 등을 필요로 하는지 파악하기는 어려울 수 있습니다. 올바른 파일 디렉토리는 정보를 숨기는 게 아니라 드러내야 합니다.

기능별 폴더 구조는 흔하지는 않지만 언뜻 합리적인 유형으로 보입니다. 많은 기업이 기능에 따라 팀을 나누므로 데이터도 유사하게 그룹화하는 것이 좋다고 생각할 수 있습니다. 하지만 게임에서는 데이터가 그렇게 사용되지 않습니다. 저는 함께 번들링되어야 할 셰이더나 오디오를 서로 다른 팀에서 저작(authoring)하는 바람에 따로 그룹화되는 사례를 본 적이 있습니다.

에셋의 용도에 따라 파일 디렉토리에 명확한 명명 규칙을 갖춘다면 이러한 문제가 생길 일이 없습니다. ‘Dinosaur Brawl’이라는 가상의 게임을 예로 들어 이 부분을 자세히 알아보겠습니다.

Dinosaur Brawl

Dinosaur Brawl이라는 가상의 3인칭 3D 액션 어드벤처 게임을 생각해 보죠. 이 게임에서 플레이어는 공룡 한 마리를 선택해 다양한 생물군으로 가득한 광활한 오픈 월드를 누빌 수 있습니다. 힘을 키우고 다음 세대에 유전자를 물려주기 위해 다른 공룡이나 선사 시대 생물과 싸우게 되기도 합니다. 이렇게 다가오는 빙하기에 맞서 살아남기 위해 고군분투하는 스토리의 게임입니다. 모바일용으로 설계된 게임이며 일부 데이터가 원본 애플리케이션과 함께 배포됩니다. 나머지 데이터는 필요에 따라 CDN에서 다운로드됩니다.

위에서 제시된 게임 시나리오에 맞게 전체 프로젝트의 개략적인 폴더 구조를 생각해 봅시다. 플레이어가 공룡을 선택해 다른 공룡과 싸울 수 있으므로 메시, 음향 효과, 텍스처, 애니메이션, 파티클 효과 등 특정 공룡에 사용되는 모든 에셋이 담긴 폴더를 공룡마다 만드는 것이 좋습니다. 이를 고유 에셋으로 분류하겠습니다.

액션 게임이므로 각 생물군에 맞는 환경이 있을 것입니다. 따라서 평원, 사막, 툰드라, 늪지대, 화산 등 프로젝트의 생물군이나 레벨마다 폴더를 하나씩 만들어야 하죠.

물론 게임의 모든 섹션에 필요한 에셋도 있습니다. 예를 들면 UI 요소입니다. 이러한 에셋은 전역 에셋으로 분류합니다. 고유 에셋마다 폴더를 만든 것처럼 폴더 계층 구조의 최상위에 전역 폴더가 하나씩 있어야 합니다. 이를테면 전역 UI 폴더, 전역 공룡 폴더, 전역 환경 폴더 등입니다. 이렇게 하면 게임 섹션에서 공유되는 모든 에셋이 한곳에 저장됩니다.

공유 에셋

공유 에셋은 일부 고유 에셋에서는 공유되지만 모든 에셋에서 공유되지는 않는 에셋을 말합니다. 따라서 전역 에셋 또는 고유 에셋의 범주에 속하지 않습니다. Dinosaur Brawl에서는 공중을 날아다니는 느낌을 부여하는 파티클, 셰이더, 음향 효과처럼 모든 익룡에 사용되는 에셋을 공유 에셋의 예로 들 수 있습니다.

보통 이런 종류의 에셋은 처음으로 이 에셋을 사용하는 공룡의 폴더에 저장됩니다. 그러나 그러면 용도가 명확하게 전달되지 않으므로 에셋의 용도를 알기 어려워집니다. 최악의 경우 익룡 번들마다 에셋이 중복으로 생성되어 메모리, 디버깅, 애플리케이션 크기 측면에서 비효율이 발생합니다.

가장 좋은 해결법은 ‘익룡’처럼 용도가 드러나는 이름으로 새 폴더를 만드는 것입니다. 구체적인 위치를 결정하는 것은 정해진 표준이 없으므로 조금 더 까다롭습니다. 저는 전역 공룡 폴더 및 고유 공룡 폴더와 동일한 수준의 하위 폴더에 넣는 것을 선호하지만, 다른 고유 폴더와 함께 저장하는 것도 적절한 방법일 수 있습니다.

용도 변경

이 규칙이 필요한 일반적인 에지 케이스는 프로젝트의 요구 사항이 변경되어 기존의 고유 에셋이 공유 에셋으로 변경되는 것입니다. Dinosaur Brawl 예제에서는 개발 시간을 단축하기 위해 벨로시랩터 프리팹을 유타랩터, 다코타랩터 등 다른 모든 랩터의 기반으로 사용하기로 했습니다.

그러나 개발자들은 벨로시랩터 프리팹을 번들에 추가하면 다른 모든 랩터가 로드될 때 벨로시랩터 에셋도 모두 다운로드되므로 프리팹만 사용하더라도 다운로드 시간이 늘어난다는 것을 깨닫지 못했습니다.

에셋의 용도가 변경되었는데 폴더 구조가 이를 반영하지 못해 생긴 일이었죠. 용도가 변경되면 이에 따라 에셋의 위치와 이름을 업데이트해야 시스템의 일관성과 정확도를 유지할 수 있습니다. 이렇게 하면 번들 제작 팀이 어떤 에셋을 ‘공유 랩터’ 번들에 넣고 어떤 에셋을 고유 벨로시랩터 모델에 남겨야 하는지 알 수 있습니다.

용도 외의 사용

가장 흔하면서도 해결하기 어려운 에지 케이스는 의도치 않게 처음 생각한 것과는 다른 용도로 에셋이 사용되는 경우입니다. 이런 일은 보통 사고로 발생합니다. 예를 들어 마감 기한을 지키기 위해 프로젝트의 기존 에셋을 사용해 작업을 빠르게 완료하려고 하면 이런 일이 벌어질 수 있습니다. 

다음 시나리오를 가정해 봅시다. 아티스트가 Dinosaur Brawl의 다음 확장팩에 튜토리얼을 추가하려고 하는데, 플레이어가 정예 몬스터에게 반격하는 데 성공했을 때 이를 강조하는 ‘gold glow’ 셰이더를 발견했습니다. 문제는 이 셰이더가 다양한 에셋이 번들링된 고유 보스인 대형 티라노사우루스와 싸울 때 사용되는 게임의 최종 콘텐츠라는 것을 아티스트가 몰랐던 겁니다. 이제 튜토리얼 단계에서는 필요하지 않은 대부분의 에셋도 모두 함께 다운로드됩니다. 게임 도중에 마이너 에셋을 다운로드하는 시스템은 보통 이렇게 큰 용량의 번들을 다루지 않기 때문에 갑자기 불안정해지고, 연결 상태가 열악한 플레이어는 에셋을 빠르게 다운로드할 수 없어 성능 스파이크부터 크래시까지 다양한 문제를 겪게 됩니다.

위 예시는 극단적이면서도 지극히 현실적인 예시이며, 저는 여러 프로젝트에서 이런 일이 발생하는 것을 실제로 목격한 적이 있습니다. 이 때문에 폴더 구조 외에도 모든 에셋에는 그 용도를 드러내는 명명 규칙이 필요합니다. 만약 셰이더의 이름이 gold_glow_trex_endgame이었다면 용도가 더 명확하게 공개되어 이 에셋을 튜토리얼 단계에서 로드하면 안 된다는 사실을 디버깅 시에 깨달을 수 있었을 겁니다.

프로그래밍 솔루션

여러분이 어드레서블에 익숙하다면 그룹과 레이블을 통해 위의 게임 예제에서 제안한 것과 유사한 방식으로 폴더와 적절한 명명 규칙을 활용해 에셋을 그룹화하고 레이블을 지정할 수 있다는 걸 알고 계실 겁니다. 그렇다면 “그룹과 레이블을 사용하면 되는데 왜 이걸 모두 신경 써야 하나요?”라고 질문할 수 있습니다.

답변을 드리자면 둘 다 해야 합니다. 처음에 설명한 것처럼 프로젝트의 에셋 수가 늘어날수록 한 사람이 모든 에셋의 용도를 파악하기가 점차 어려워지다 결국은 아예 불가능해집니다. 어드레서블 그룹이 폴더 구조와 일치해야 한다는 걸 알고 있으면 해당 그룹이 올바르게 구성되었는지 확인할 수 있습니다.

저는 에셋 번들을 사용하는 고객이 이 문제를 해결하기 위해 어드레서블 없이 복잡한 시스템으로 코드를 작성하는 것을 자주 목격했습니다. 번들을 제작할 때 사용되는 마스터 목록을 만들어 관리하거나 번들의 변경 사항을 비교하기 위해 버전 관리 커밋을 확인하는 경우도 있습니다. 제 경험에 따르면 이러한 해결 방식은 장기적으로 비용 효율적이지 않습니다. 별도의 시스템을 개발하고 유지해야 하므로 오류가 발생할 수 있는 가능성이 높아지는 셈입니다. 프로젝트 규모가 커짐에 따라 장기 프로젝트에서 자연스럽게 축적되는 다양한 예외와 에지 케이스를 처리해야 할 뿐 아니라 사용자 오류에 대한 해결책이 없어 결국 문제가 생기기 마련입니다.

결론

폴더 시스템과 파일 명명 규칙이 제대로 구축되어 있다면 에셋 번들과 어드레서블 그룹이 일대일로 대응해야 합니다. 파일을 논리적으로 그룹화하고 하위 폴더에 분류하면 모든 팀원이 파일을 일관되게 이해하고 그 위치를 파악할 수 있으며, 담당자나 프로젝트 요구 사항이 변경되더라도 잠재적인 오해와 불일치를 최소화할 수 있습니다. 에셋 제작 단계에서 에셋에 쉽게 액세스하여 찾을 수 있도록 구성하면 다른 팀원이 특정 에셋을 찾는 데 걸리는 시간도 단축할 수 있습니다. 체계적인 접근 방식을 통해 귀중한 시간을 절약하고 오류와 실수가 발생할 가능성을 최소화할 수 있습니다. 이 구조를 지속적인 기준점이자 SSOT로 활용하면 새 팀원을 원활하게 온보딩할 뿐 아니라 시간이 흘러도 프로젝트의 실행 가능성을 그대로 보장할 수 있습니다.

폴더 구조에 대한 지원이나 조언이 필요하신가요? 포럼에 참여해 보세요. 현재 연재 중인 Tech from the Trenches 시리즈에서 다른 Unity 개발자들의 새로운 기술 블로그도 확인할 수 있습니다.

2023년 12월 28일 엔진 & 플랫폼 | 16 분 소요

Is this article helpful for you?

Thank you for your feedback!

관련 게시물