Thrive를 위한 맞춤형 식생 시스템으로 성능 최적화: 무거운 왕관

ADAM AXLER / UNITYSenior Content Marketing Manager
Jun 18, 2025
Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
이 웹페이지는 이해를 돕기 위해 기계 번역으로 제공됩니다. 기계 번역으로 제공되는 콘텐츠에 대한 정확도나 신뢰도는 보장되지 않습니다. 번역된 콘텐츠의 정확도에 관해 의문이 있는 경우 웹페이지의 공식 영어 원문을 참고해 주시기 바랍니다.

Zugalu Entertainment는 혁신, 향수, 상업적 매력을 혼합한 게임을 만들기 위해 2014년에 설립되었습니다. 지난 11년 동안 그들은 Epic Food Fight, Technolites, Chronique des Silencieux, 및 Sovereign Syndicate를 포함한 타이틀을 출시했습니다.

2024년 11월 6일, 그들은 Thrive: Heavy Lies the Crown을 얼리 액세스에서 출시하였고, 좋은 평가를 받았습니다. 이 게임은 실시간 전략 요소가 포함된 중세 도시 건설 게임으로, 싱글 플레이어 및 협동 멀티플레이어 기능을 제공합니다. 플레이어는 전략적으로 자신의 영토와 왕국을 확장하고, 큰 지도에 따라 건설할 수 있습니다. 여행이 진행됨에 따라 왕국의 운명은 그들이 내리는 모든 결정에 달려 있습니다.

오늘, 팀은 게임의 1.0 버전을 출시했습니다. 우리는 Zugalu Entertainment의 CTO인 Garrett Hau와 팀의 리드 컨셉 아티스트이자 기술 아티스트인 Jackie Li와 함께 성능 문제와 맞춤형 식생 시스템 구축이 게임 최적화의 핵심이었던 방법에 대해 이야기했습니다.

맞춤형 식생 시스템 구축

게임이 황야를 배경으로 하고 있기 때문에 나무, 풀, 덤불 등이 많이 있습니다. 원래 구현에서는 풀이 매우 드물었지만, 팀은 넓고 무성한 풀밭을 만들고 싶어했습니다. “풀밭 생태계와 같은 다양한 생태계에 대해 우리는 땅을 식생으로 가득 채우고 싶었습니다.”라고 Hau가 말합니다. 이를 달성하기 위해 그들은 높은 수의 식생 인스턴스를 처리할 수 있는 시스템이 필요했습니다.

프로젝트의 대부분 동안 팀은 잘 작동하는 서드파티 솔루션을 사용했지만, CPU에 크게 의존하고 있었고, 약 3밀리초의 비용이 들었으며, 게임은 매우 CPU 병목 현상이 있었습니다. 상당히 낮은 시스템 요구 사항이 있었기 때문에, 그들은 대부분의 계산을 GPU로 이전하기로 결정하고 다른 종류의 솔루션이 필요했습니다.

“우리는 자체 시스템을 만들기로 결정했고, 동시에 게임의 타일 기반 특성과 통합했습니다. 원래 시스템은 자체적인 작동 방식이 있었고, 타일 수준에서의 특정 상호작용은 너무 비용이 많이 들었습니다.”라고 Hau가 말합니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
식생의 인-에디터 미리보기

그들은 그것을 수정하고 더 높은 밀도의 식생을 가질 수 있기를 원했습니다. 그들은 새로운 시스템에서 GPU에서 계산하고 있었기 때문에 더 많은 성능 여유가 있었고, 번성하는 숲을 만들 기회가 있었습니다.

또 다른 주요 목표는 타일별 마스킹을 얻는 것이었습니다. “이전에는 도로를 놓을 때 효율적으로 마스킹할 수 없어서 식생이 도로 위로 자라기만 했습니다.”라고 하우가 말합니다. 초기 방법이 CPU에 의존했기 때문에 추가적인 마스크가 CPU에 부담을 주었고, 그들은 도로 또는 실제로 무엇이든 잔디나 식생을 마스킹할 수 있기를 원했습니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
팀 타일 마스킹의 인-에디터 샷

컴퓨트 셰이더로 실행 중

팀은 또한 넓은 맵에 걸쳐 식생을 생성할 때 주요 병목 현상을 경험했습니다. 게임에 식생이 풍부하고 카메라가 맵을 빠르게 이동할 수 있기 때문에 식생이 플레이어를 멈추지 않고 생성되는 것이 중요했습니다. 이것은 매우 어려운 일로 판명되었습니다.

“식생을 보면 수십만 개의 인스턴스를 생성해야 한다는 것을 알 수 있습니다. 그래서 우리는 이 정확한 목적을 위해 설계된 GPU 인스턴싱을 선택했습니다. 이는 잠재적으로 수백만 개의 인스턴스를 허용합니다.”라고 리가 말합니다.

시작하기 위해 팀은 GPU 인스턴싱을 위한 데이터를 준비했습니다. 그들은 식생을 생성하고자 하는 모든 위치의 배열을 GPU에 구성하고 제공해야 했습니다. 식생은 타일 마스킹 외에는 CPU 측과 실제로 상호작용하지 않기 때문에, 그들은 이를 컴퓨트 셰이더로 실행했습니다. 컴퓨트 셰이더가 렌더 셰이더가 실행되기 전에 GPU에서 실행되었기 때문에, 그들은 컴퓨트 셰이더에서 데이터를 준비한 다음 인스턴싱을 위한 결과 데이터를 제공했습니다. 이것은 인스턴스 간접이라고도 알려져 있습니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
스폰된 유닛의 인-에디터 샷

다음 단계는 컴퓨트 셰이더를 사용하는 방법을 알아내는 것이었으며, 이는 상대적으로 쉬운 것으로 판명되었습니다. Li는 "컴퓨트 셰이더는 GPU에서의 다중 스레드 작업일 뿐입니다."라고 설명합니다. 우리의 경우, 각 인스턴스 데이터는 각 스레드에서 개별적으로 계산될 수 있습니다. GPU에서 Unity 작업 시스템처럼 생각해 보세요."

다중 스레드 환경에서 작업할 때, 각 스레드의 작업량은 성능을 극대화하기 위해 다른 스레드의 실행에 의존하지 않도록 설계되어야 합니다.

Li는 "예를 들어, 무작위성을 추가할 때 우리는 퍼린 노이즈, 심플렉스 노이즈 또는 해시 함수와 같은 것들을 사용할 것입니다."라고 말합니다. 현재 평가된 표면은 균일한 그리드로 나뉘며, 각 스레드는 각 그리드 포인트 내에서 작동하여 서로 겹치는 중복 식생을 스폰하는 것에 대해 걱정할 필요가 없습니다.

지형이 런타임에 변형될 수 없었기 때문에, 그들은 개발 시작 시 이 데이터를 가져와 GPU에 전달했습니다. 이것은 각 높이 위치에서 경사를 계산하기 위한 높이 데이터의 전처리를 가능하게 하여, 식생이 지형의 윤곽을 따르도록 사용자 정의할 수 있었습니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오

컴퓨트 셰이더 통합


팀이 컴퓨트 셰이더를 사용하고 있었지만, 원하는 데이터를 얻기 위해 많은 셰이더를 실행해야 했습니다. 드로우 호출과 유사하게, 적을수록 좋습니다. 그들은 GPU 명령의 수를 줄이기 위해 배포 호출의 절반을 제거하고 CPU 데이터 전송을 GPU로 하나의 API 호출로 결합하려고 했습니다.

"우리의 식생 시스템은 많은 다양한 유형의 식생으로 구성되어 있으며, 각 유형의 식생은 컴퓨트 배포가 필요합니다."라고 Li는 설명합니다. "50개의 식생이 있다면, 50개의 배포가 필요하며, 각 배포는 n개의 스레드를 가집니다."

각 스레드의 목표는 인스턴스 위치와 기타 데이터를 계산하는 것이었지만, 스레드가 마스크된 위치이거나 카메라 프러스텀 밖에 있는 잘린 위치를 계산할 가능성이 높았으며, 이 경우 데이터는 나중에 식생을 그리는 데 사용되는 인스턴스 배열에 추가되지 않습니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오

스레드가 배열에 추가할 수도 있고 추가하지 않을 수도 있기 때문에, 우리는 유효한 값을 목록에 추가하는 스레드 안전 리스트와 같은 데이터 구조를 사용했습니다. HLSL은 편리하게도 추가 버퍼 형태로 이 기능을 제공합니다. “추가 버퍼를 사용하는 것은 작은 단점이 있다”고 Li가 말합니다. “추가된 항목의 수를 가져오고 그 수를 지워서 추가 버퍼를 재사용할 수 있도록 하기 위해 추가 GPU 명령을 실행해야 했습니다.”

그러나 컴퓨트 셰이더는 스레드 간 통신을 가능하게 하는 groupshared라는 편리한 변수를 제공했습니다. 그리고 그것은 Interlocked 함수와 결합되어 각 디스패치가 전역 인덱스 카운터를 추적할 수 있게 하여 유효한 인스턴스 데이터를 밀집하게 포장하고 간접 드로우 명령을 업데이트할 수 있게 했습니다. 이는 인스턴스 위치를 계산하는 동일한 디스패치 호출 내에서 이루어졌습니다.

CPU 데이터를 전송할 때 팀은 처음에 성능 저하에 직면했습니다. 그들은 프레임마다 변경되는 다양한 식물 유형에 대한 셰이더 속성을 업데이트해야 했습니다.

“원래는 데이터를 별도로 전송하여 50개의 SetData() 명령을 발생시켰습니다.”라고 Li가 말합니다. “그러나 기본 데이터 유형이 동일했기 때문에 모든 데이터를 하나의 버퍼로 통합한 다음 각 식물 유형에 대해 해당 버퍼의 오프셋 인덱스를 제공했습니다. 이로 인해 단 하나의 SetData() 명령만 필요했습니다.”

팀은 보수적으로 CPU 시간에서 0.1밀리초를 절약했다고 추정하며, 이는 총 0.5밀리초의 20%를 나타냅니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오

CPU에서 GPU로 타일 데이터 전송

지도는 매우 커서 약 1000만 개의 타일이 있었기 때문에 팀은 CPU에서 GPU로 타일 데이터를 가져오는 데 어려움을 겪었습니다. “프레임당 수백만 개의 타일을 GPU로 전송하려고 하는 것은 매우 비용이 많이 들 것입니다. 왜냐하면 전송해야 할 데이터가 많기 때문입니다. 화면을 차지할 만큼의 데이터 하위 집합을 전송할 수 있어야 했습니다.”라고 Hau가 말합니다.

그들은 이를 달성하기 위해 Unity의 작업 시스템을 사용했습니다. 이 시스템은 CPU 측에 도움이 되었고 데이터를 가져와 GPU로 전송하는 멀티스레드 방식을 제공했습니다. Hau는 "배열에서 데이터를 가져오는 것은 Job System에 의해 가속화될 수 있는 완벽한 작업 부하입니다."라고 설명합니다.

각 스레드는 데이터의 일부를 가져오기 위해 실행될 수 있으며, 그 데이터는 목적지 배열로 복사됩니다. 동시에, 그들은 원래의 16비트 데이터를 컴퓨트 셰이더에서 사용되는 패킹된 32비트 데이터로 변환했습니다.

팀은 또한 Job System 데이터에 Burst Compiler를 적용하여 최적화된 코드를 생성했습니다. "Burst Compiler는 다중 스레드 성능을 크게 향상시켰습니다. 속성을 추가하자마자, 1밀리초 이상에서 0.3밀리초 미만으로 빠르게 줄어들었습니다." 단 한 줄의 코드를 추가한 것만으로도 매우 인상적이었습니다."라고 Hau가 말합니다.

Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오
Thrive: 무거운 왕관 | 주갈루 엔터테인먼트 | 플레이사이드 스튜디오

팀이 큰 최적화 성과를 경험했지만, 모든 식생을 렌더링하는 성능은 주의해야 할 사항입니다.

"성능 절약에 기뻐하고 있지만, 오버드로우는 여전히 제 시스템이 해결하지 못하는 문제입니다."라고 Li가 설명합니다. "우리는 그것을 염두에 두어야 합니다. 그럼에도 불구하고, 우리는 게임이 어떻게 나왔는지에 대해 매우 기쁩니다."

Unity로 제작된 프로젝트에 대해 더 읽으려면 리소스 페이지를 방문하세요.