DrakkenRidge: 모바일 VR을 위한 오픈 월드 어드벤처 구축
Simeon Acker and Cyril Guichard - Garage Collective
GUEST BLOG
Key art for DrakkenRidge VR by Garage Collective, Made with Unity. Composite image featuring a logo overlaid on a mountain landscape background. The lower thirds blend into a parchment texture. Within the circular logo is a blonde haired elf, a red-bearded dwarf, and a wizard with a white beard.
Unity로 제작된 DrakkenRidge는 Garage Collective의 오픈 월드 액션 RPG로, 모바일 VR에 맞춰 설계 및 최적화되었습니다. 본 게스트 블로그에서 팀은 Unity의 Entity Component System을 렌더링의 백본(backbone)으로 활용하면서 다양한 디자인 및 성능 기술들을 어떻게 활용했는지 공유합니다.
DrakkenRidge trailer
DrakkenRidge VR 소개
저희는 DrakkenRidge를 만든 Garage Collective입니다. 이 게임은 오픈 월드 액션 RPG로, 플레이어가 지평선에서 보는 모든 장소에 방문할 수 있도록 VR을 위해 제작되었습니다. 강력한 마법 사냥꾼(Mage Hunter)의 역할을 맡아 탐험하며, 각각 완전히 독특하고 자신만의 캐릭터, 퀘스트, 던전, 비밀을 가진 여섯 개의 아름답게 손질된 섬들을 돌아다닐 수 있습니다.
이 여정은 따뜻하고 편안한 해변에서 숨 막히는 설원 봉우리까지; 무성하고 신비로운 숲에서 지구 깊은 곳의 위험한 협곡까지 플레이어를 안내할 것입니다. 새로운 아이템을 제작하고, 예술적으로 디자인된 수십 마리의 생물체와 적들과 전투하며, 모든 만남을 독특한 경험으로 바꿀 수 있는 새로운 마법 학파들을 해제하세요.
이 정도 규모의 게임을 두 명의 팀이 만드는 것은 Entity Component System 없이는 불가능했을 것입니다. 본 게시물에서는 저희가 이 확장된 어드벤처 게임을 만들기 위해 이러한 도구들을 어떻게 사용했는지 다룰 것입니다.
Drakkenridge | Building an Open World VR RPG with DOTS
더 부드러운 게임 개발을 위한 기술 혼합
ECS를 사용하여 게임을 구축할 때 여러 가지 큰 장점들이 있지만, 소규모 독립 스튜디오인 저희는 DrakkenRidge를 모바일 VR용으로 설계하고 엔지니어링하는 과정에서 다른 요소들도 신중하게 고려해야 했습니다.
ECS를 사용할 때 두 가지 주요한 어려움이 있습니다:
- 가파른 학습 곡선: ECS로 개발하려면 일반적인 객체 지향(object-oriented) 로직에서 완전히 벗어난 패러다임 전환이 필요합니다.
- Entity 시스템과 전통적인 게임 오브젝트 시스템 간의 분리는 이들 간의 상호작용을 어렵게 만들 수 있습니다.
그래서 저희에게 남겨진 질문은 다음과 같았습니다:
어떤 오브젝트와 상호작용이 ECS의 힘을 활용해야 하며, 어떤 오브젝트는 전통적인 GameObject 및 MonoBehaviour로 남아 있어야 할까요?
DrakkenRidge의 엔티티(Entities)
DrakkenRidge는 방대한 오픈 환경으로 구성되어 있으며, 주어진 공간에 수만 개의 오브젝트가 존재합니다. 이 중 플레이어에게 어느 순간에도 수천 개가 보일 수 있습니다.
이러한 오브젝트들을 전통적인 GameObject로 렌더링하려면 큰 메모리 오버헤드가 발생하며, 엔진은 전체 씬 계층 구조를 평가하고 각 오브젝트의 Transform 컴포넌트를 계산해야 합니다. 특히 모바일 장치에서 수천 개의 오브젝트를 렌더링할 때 GPU에 눈에 띄는 부담을 줄 수 있습니다.
그렇다면 이 오브젝트들을 엔티티(Entities)로 가져가서 렌더링한다면 어떨까요?
DrakkenRidge VR
엔티티로 만들 경우, GameObject와 관련된 많은 렌더링 및 메모리 오버헤드를 피할 수 있으며, 대신 Entities Graphics* 시스템을 사용하여 메모리 청크(memory chunks) 단위로 배치됩니다.
게다가 DrakkenRidge의 아트 파이프라인은 텍스처 아틀싱(Texture Atlassing) 기법을 광범위하게 활용하여 방대한 환경이 전체적으로 적은 수의 머티리얼(Materials)을 사용하도록 합니다 (여기에 있는 텍스처 아틀싱에 대한 블로그 게시물을 참조하세요).
Entities Graphics는 공통된 메시와 머티리얼을 공유하는 모든 오브젝트를 그룹화하고 처리할 수 있으며, 그러면 엔진은 조밀하게 채워진 드로우 콜(draw calls)을 생성하여 많은 오브젝트들을 한 번에 렌더링할 수 있습니다.
그 결과로 수백 개의 배치(batches)와 SetPass 호출을 절약할 수 있습니다.
Screenshot of DrakkenRidge from Garage Collective, Made with Unity. 3D rendering of a rocky hillscape. A window in the corner shows the small number of SetPass calls (8) against thousands of objects.
수천 개의 오브젝트를 렌더링 – 단 8개의 SetPass 호출만으로
사용자 정의 엔티티 시스템 (Custom Entity systems)
DrakkenRidge는 한 번에 수많은 오브젝트들을 렌더링하기 위해 ECS를 활용합니다. 하지만 이렇게 엄청난 성능 향상을 얻었음에도 불구하고, 모바일 VR 플랫폼에서 경험을 개선할 수 있는 여지는 아직 더 남아 있습니다.
거리 기반 작성 시스템 (Distance authoring system)
DrakkenRidge 엔티티를 위해 우리가 만든 첫 번째 기능은 거리 기반 작성 시스템입니다. 이 시스템은 오브젝트가 플레이어에게 보여야 할지 숨겨져야 할지를 결정하기 위해 다양한 변수들을 고려합니다.
플레이어의 시야가 오픈 월드에서 매우 멀리 뻗어나가기 때문에, 수천 개의 먼 객체가 한 번에 보이는 상태일 수 있습니다. 이 시스템은 이들 중 어떤 것이 눈에 잘 띄게 유지되어야 하고, 어떤 것이 배경으로 사라져야 하는지를 우선순위를 지정합니다. 원거리 안개(distance fog)와 같은 환경 효과를 사용하여 멀리 있는 객체들이 시야에서 사라지는 전환 과정을 처리합니다.
In-game screeenshot from DrakkenRidge VR by Garage Collective. Made with Unity. Overlaid is a window showing distance Authoring component with custom values for runtime Entity culling.
런타임 엔티티 컬링을 위해 사용자 정의 값을 가진 거리 작성 컴포넌트 (Distance Authoring component)
각 엔티티(Entity)마다 다양한 매개변수를 기반으로 에디터 내에서 고유한 컬링 값이 생성됩니다. 이 데이터는 이후 엔티티 생성 시점에 시스템*에 전달되며, 시스템은 이 사전 계산된 데이터를 사용하여 엔티티를 언제 렌더링하거나 컬링할지 런타임 결정을 내립니다.
사용자 정의 엔티티 그룹 (Custom Entity groups)
DrakkenRidge의 거리 작성 시스템을 사용하면, 엔티티들을 공유되는 의사결정 처리를 가진 그룹에 할당할 수 있습니다. 이를 통해 예를 들어 도시의 특정 구역 전체를 개별적으로 결정하는 대신, 다양한 게임 내 요인에 따라 빠르게 렌더링하거나 컬링할 수 있게 합니다.
In-Editor screenshot from DrakkenRidge VR, made with Unity. A townscape with blue collider boxes around an inn. On the left is an inspector window showing grouped entities with shared decision-handling.
공유 의사결정 처리를 가진 그룹화된 엔티티 (Grouped Entities with shared decision-handling)
엔티티 LOD (Entity LODs)
DrakkenRidge의 거리 작성 시스템의 세 번째 기능은 엔티티가 렌더링 비용이 더 저렴한 다른 엔티티로 실시간으로 교체될 수 있도록 합니다. 이 기술은 원래 더 비싼 셰이더와 재질(materials) 문제에 대처하기 위해 작성되었습니다.
DrakkenRidge의 환경 모델들은 이미 고도로 최적화되어 있지만, 일부 셰이더는 눈에 띄는 비용을 추가합니다. 이 엔티티 LOD (Level of Detail, 세부 수준) 시스템은 필요할 때만 “비용이 더 높은 셰이더를 가진 엔티티 버전”을 렌더링할 수 있도록 합니다.
/// 만약 간소화된 LOD 객체를 사용한다면, 우리가 그 범위 내에 있는지 확인합니다.
if (inDistanceReturn.useLOD)
{
...
조건이 충족되면 엔티티에 대해 간소화된 LOD를 사용합니다.
CPU 최적화
DrakkenRidge의 거리 작성 계산은 최대 CPU 성능을 위해 버스트 컴파일된 Job(작업)을 통해 실행됩니다.
Unity Jobs는 비동기 작업으로 예약되어 백그라운드에서 실행될 수 있는 함수이며, Burst Compiler*는 이러한 CPU 집약적 작업을 고도로 최적화된 네이티브 기계 코드로 변환하여 가속합니다.
[BurstCompile]
public partial struct ProcessBufferJob : IJobChunk
{
...
팁: DynamicBuffer를 반복하기 전에 NativeArray로 캐스팅하는 것이 하나의 최적화 방법입니다: “var lodChildNativeArray = lodChildBufferData.AsNativeArray();”
DrakkenRidge의 GameObjects와 물리(Physics)
DrakkenRidge에서는 월드의 90%가 ECS를 사용하여 렌더링되며, 가시적인 환경을 아름답고 최적화된 상태로 유지하기 위해 자체적으로 백그라운드에서 작업을 실행합니다.
하지만 프로그래머 한 명과 아티스트 한 명으로 구성된 저희의 작은 개발팀은 많은 근접한 VR 상호작용을 전통적인 GameObjects와 MonoBehaviors를 사용하여 구축하기로 결정했습니다. 이는 빠른 테스트와 빈번한 디자인 사이클 환경에서 더 빠른 반복 시간을 가능하게 했습니다.
물리 상호작용 및 전투(Combat)
DrakkenRidge의 VR 상호작용은 주로 물리 시뮬레이션에 의해 구동됩니다. 여기에는 물체를 잡고 조작하는 것부터 플레이어의 등반과 파쿠르, 주문 시전 및 근접 전투까지 모든 것이 포함됩니다.
플레이어는 물리 기반의 등반 챌린지와 상호작용할 수 있습니다.
월드에서 물리 시뮬레이션 실행하기
DrakkenRidge의 전투는 독특한 애니메이션과 관절별(per-joint) 물리 동작을 혼합하는 시스템에 의해 구동됩니다. 각 AI는 상황에 따라 자신의 죽음이 반응적이고 보람 있게 느껴지도록 결정합니다.
관절별 물리와 스크립트된 애니메이션을 결합하여 독특한 반응 구축하기
DrakkenRidge의 많은 아이템과 주문은 플레이어가 여러 적에게 동시에 피해를 입힐 수 있게 하며, 종종 많은 캐릭터 리그(character rigs)에 대해 물리 시뮬레이션이 동시에 실행되는 결과를 낳습니다.
AI 그룹에 폭발적인 물리 적용하기
물리 최적화
실시간 물리 시뮬레이션은 특히 모바일 플랫폼에서 비용이 많이 들 수 있습니다. 이를 완화하기 위해 월드의 각 물리 객체는 플레이어의 위치와 플레이어가 해당 시뮬레이션과 상호작용할 수 있는 위치인지 여부를 추적합니다.
예를 들어, 플레이어는 서로 상호작용하는 물리 기반 링크로 만들어진 긴 체인을 오를 수 있습니다. 이러한 물리 충돌기(physics colliders), 관절(joints), 그리고 강체(rigidbodies)는 플레이어가 해당 체인을 직접 조작하거나 시야에 들어올 때만 동적으로 활성화/비활성화됩니다.
일반적인 규칙으로, 우리는 멀리 떨어진 객체를 렌더링하지만, 물리 상호작용은 가까이 있는 객체에 대해서만 허용합니다. 액션이 근거리에서 발생하는 VR 게임의 경우, 이는 플레이어가 기대하는 바와 일치합니다.
추가 최적화
모바일 VR을 위해 렌더링을 어떻게 최적화할지 결정할 때, 우리는 각 환경이 어떻게 구축되었는지 고려하고 우리에게 가장 적합한 솔루션을 선택했습니다.
ECS 외에도 LOD(Level of Detail)와 임포스터(impostors)를 포함하여 다양한 기술들을 고려했습니다.
GameObject LODs
LOD가 적용된 GameObjects를 렌더링하는 것은 주어진 객체의 여러 버전을 플레이어로부터 다른 거리에서 렌더링할 수 있도록 하는 것을 의미합니다. 예를 들어, 매우 상세한 하우스 모델은 플레이어가 객체로부터 멀리 떨어져 있을 때 렌더링 시간을 절약하기 위해 매우 단순화된 로우폴리(low-poly) 버전으로 대체됩니다.
DrakkenRidge에서는 모든 객체가 이미 고도로 최적화된 로우폴리 레트로 아트 스타일로 모델링되어 있으며, 월드의 대부분은 ECS를 통해 처리되므로 전통적인 3D LOD는 실질적인 이점을 제공하지 못합니다.
하지만 우리가 만든 거리 작성(distance authoring)* 시스템은 필요할 때 멀리 떨어진 엔티티(Entities)의 LOD 렌더링을 처리하도록 구축되었습니다.
Impostors
임포스터 시스템은 3D GameObjects를 플레이어가 충분히 떨어져 있을 때 2D 빌보드(billboards)로 변환합니다. 이는 숲과 같은 밀집되고 먼 배경 객체에 가장 효과적입니다. DrakkenRidge는 특정 상황에서 임포스터를 활용합니다.
In-game screenshot from DrakkenRidge VR by Garage Collective, Made with Unity. 3D rendering of a hilly mountainscape, with an indistinguishable impostor clearly labeled in the background.
제대로 구현된 임포스터(impostors)는 3D 원본과 구별할 수 없습니다.
DrakkenRidge에서는 다양한 최적화 기법을 테스트했으며, 어떤 것을 구현할지 신중하게 선택했습니다. Unity ECS가 전통적인 GameObject 파이프라인을 사용하는 것보다 훨씬 적은 비용으로 전체 월드를 렌더링하며 가장 큰 성능 향상을 제공했습니다.
마무리 생각