역자의 말: 중국 넷이즈 항저우 스튜디오에서 첫 중국 직장생활을 할 때 근무했던 곳이라 할 수 있다. 레이훠와 형제 스튜디오인 반구 스튜디오가 레이훠 스튜디오로 통합되었다. 자체 엔진 개발 및 언리얼 엔진과 유니티 엔진을 모두 사용하여 다수의 게임을 개발하는 스튜디오이며, 엔진센터는 주로 저장대 CAD 랩 석박사 출신들로 이루어져 있다.
저자: 넷이즈 게임 레이훠 사업군
서문:
이 글의 저자 치무는 넷이즈 레이훠의 시니어 엔진 개발 엔지니어로, 약 8년에 가까운 게임 업계 경험을 가지고 있으며 렌더링 파이프라인 개조, 개선, 최적화에 능하다.
1. RenderGraph 소개
렌더링 파이프라인을 개발하는 과정에서 우리는 보통 렌더링 파이프라인의 일련의 작업을 Pass로 캡슐화한다. 어떤 종류의 오브젝트를 렌더링하는 작업일 수도 있고, 단순히 전역 상태를 설정하는 작업일 수도 있다. 다양한 효과가 추가되고 크로스 플랫폼 지원이 늘어나면서 Pass의 로직은 점점 비대해지고, 수량도 점점 많아지며, 관리하기도 점점 어려워진다. 《영겁무간 모바일》은 GLES, Vulkan, Metal, DX11, DX12를 지원하며, 최저 화질에서도 Pass가 50개가 넘고, 최고 화질에서는 100개가 넘는다. 이 시점에서는 Pass 로직을 간소화하고, 대량의 Pass를 자동으로 관리할 수 있는 방법을 찾아야 한다.
2017년 GDC에서 유비소가 먼저 프로스트바이트 엔진의 FrameGraph 기술을 공유했다. 이 기술은 전통적인 Pass가 짊어지고 있던 무거운 로직을 효과적으로 분해했고, 복잡한 렌더링 파이프라인의 개발 효율을 크게 끌어올렸다. 이후 업계에서는 점차 유사한 아키텍처를 채택하게 되었는데, 예를 들면 Unreal의 Rendering Dependency Graph와 Unity의 RenderGraph가 있다.

RenderGraph 소개
RenderGraph의 핵심 아이디어는 전통적인 Pass 안에 있던 일부 로직을 넘겨받아 Setup -> Compile -> Execute의 세 가지 큰 흐름으로 재구성하는 것이다. 먼저 Pass의 Setup을 통해 리소스 관련 요구사항과 Attachments 선언을 수집하고, 이후 Compile을 통해 최적의 리소스 할당과 상태 설정을 결정한다. 마지막으로 Pass의 Execute를 실행하면서, 그 전후에 리소스 요청과 해제, Attachments 설정 같은 자동화 작업을 삽입한다. 이 아키텍처 아래에서 파이프라인 개발자는 그림의 빨간색 부분만 커스터마이즈하면 되고, 나머지 로직에는 신경 쓰지 않아도 된다. 이를 Graph라고 부르는 이유는 Compile 결과에서 Pass의 흐름과 Resource 의존성이 하나의 방향성 비순환 그래프를 구성하기 때문이다.

RenderGraph 흐름
RenderGraph의 핵심 목적은 더 나은 성능이 아니라 개발 효율을 높이는 것이다. 이론적으로는 오히려 전통적인 파이프라인보다 CPU 성능이 더 나쁠 수 있다. 우리가 조사할 때 Unity 공식 RenderGraph와 기본 파이프라인을 비교해본 적이 있는데, 결과적으로 CPU 성능이 거의 두 배 가까이 차이났다. 모바일에서도 RenderGraph를 사용할 수 있도록 하기 위해, 우리는 URP를 기반으로 커스텀 버전의 RenderGraph를 다시 설계하고 구현했으며, 최종적으로 전 플랫폼에 안정적으로 적용했다.
2. RenderGraph 아키텍처 설계
2.1 전체 설계
전통적인 Pass에는 환경 설정, 플레이어 상호작용 등 많은 로직이 포함되어 있다. 하지만 RenderGraph의 저수준 레이어는 Pass의 리소스 관련 작업과 데이터에만 관심을 둔다. UE와 Unity 공식 구현은 함수 콜백 방식으로 양쪽 사이의 통신을 처리하지만, 이런 방식은 개발자에게 충분히 친화적이지 않고, 코드 응집도도 부족하며, 우리처럼 기존 파이프라인을 개조하는 상황에는 적합하지 않다. 그래서 우리는 컴포넌트 패턴을 선택했고, 가벼운 프록시인 PassBuilder를 통해 상위 Pass와 하위 RenderGraph 사이의 통신을 구현했다.
- 상위 레이어는 RenderGraphPass를 수집하고, PassBuilder를 통해 리소스를 선언한다.
- 하위 레이어는 데이터를 컴파일하고, PassBuilder를 통해 RenderGraphPass의 렌더링 요구사항을 실행한다.

전체 설계
2.2 리소스 시스템
렌더링 파이프라인의 모든 작업은 리소스를 중심으로 전개된다. 전통적인 Pass는 모든 단계에서 리소스 객체를 직접 조작한다. 반면 RenderGraph는 리소스를 단계별로 집중 관리하기 위해 리소스 “참조” 방식을 사용한다.

리소스 시스템 Ref
해당 프레임에서 사용하는 리소스는 리소스 시스템이 직접 관리한다. 여기에는 ComputeBuffer와 RenderTexture가 포함되며, 프레임 내부 및 카메라 간 재사용을 지원한다. 프레임을 넘나드는 RT는 각 카메라가 직접 관리하고, 카메라 렌더링이 시작되기 전에 리소스 관리 시스템 안으로 import한다.
- Setup에서 리소스를 선언하고 Ref를 반환한다.
- Compile에서 리소스 요청과 회수 시점을 결정한다.
- PreExecute에서 Ref에 실제 리소스를 할당한다.
- Execute에서 Ref를 통해 실제 리소스를 가져온다.
- PostExecute에서 리소스를 회수한다.

리소스 시스템 설계
2.3 Compile 모듈
Compile 모듈은 Setup 단계에서 수집한 PassData 데이터를 Execute 단계에서 사용할 CompiledInfos로 처리하는 역할을 맡는다. 여기에는 네 가지 단계가 포함된다.
- 리소스 참조 통계와 Pass 제거. 리소스의 생산 Pass와 소비 Pass를 기록하고, 생산한 리소스를 소비하는 Pass가 없는 Pass를 제거한다.
- 리소스 생명주기 계산. 리소스를 가장 먼저 생산하는 Pass를 생성 시점으로 삼고, 가장 늦게 소비하는 Pass를 파괴 시점으로 삼는다.
- Pass 병합 및 subpass 분할. Pass의 Attachments 선언을 기반으로, 연속된 Pass 중 동일한 선언을 가진 Pass들을 하나의 블록으로 병합한다. subpass의 경우 동일한 순서의 부분집합도 허용할 수 있다.
- LoadStoreAction 등의 상태 계산. 예를 들어 뒤쪽에 현재 블록의 Attachments를 소비하는 Pass 블록이 없다면, StoreAction은 Dontcare로 표시할 수 있다.

Compile 모듈
Compile의 연산량은 다소 크다. 모바일에서도 사용할 수 있도록 하기 위해 우리는 Dirty Compile 메커니즘을 설계했다. Setup 단계에서 수집한 데이터가 변경되었을 때만 Compile을 수행하는 방식이다. 주로 다음 세 가지 데이터를 감시한다.
- Pass 활성화 상태. 변화는 주로 디스토션 같은 특수 효과가 나타나거나 사라질 때 발생한다.
- PassData 데이터. 주로 리소스 읽기/쓰기 선언과 Attachments 선언을 포함한다. 여기에는 리소스의 구체적인 파라미터가 포함되지 않으므로 Ref만 비교하면 된다.
- Compile 설정. Pass 병합이나 리소스 상태에 영향을 줄 수 있는 일부 설정이다.

DirtyCompile
3. RenderGraph 적용 효과
3.1 코드 개발 예시
- 한 종류의 카메라는 하나의 RenderGraph에 대응한다. 이는 URP의 Renderer와 비슷하다. RenderGraph는 Pass 생산자로 볼 수 있으며, 블록을 조립하듯 RenderGraph를 구성할 수 있다. Pass는 RenderGraph 내부는 물론 RenderGraph 간에도 최대한 재사용할 수 있다.

RenderGraph 예시
- Pass 내부에서는 PassBuilder를 통해 리소스 시스템과 상호작용할 수 있다. 여기에는 리소스 요청, 리소스 읽기/쓰기 선언 등이 포함된다.

리소스 시스템 개발 예시
- Pass 내부에서는 PassBuilder를 통해 Attachments를 선언할 수 있다.

Attachments 선언 예시
3.2 실제 기기 테스트 데이터 비교
이번 개조는 주로 렌더링 파이프라인의 CPU 측면을 대상으로 했기 때문에, 비교 범위도 메인 스레드 렌더링 파이프라인 소요 시간으로 한정했다. PC에서는 Unity Profiler 툴을 직접 사용했고, Android에서는 Android Studio의 CPU Profiler 툴을 사용했으며, iOS에서는 Xcode의 Instruments를 사용했다. 모두 개발 빌드를 사용했으므로 표 안의 데이터는 상대값만 보면 된다.

데이터 비교
Dirty Compile은 성능 오버헤드를 효과적으로 낮출 수 있다. 실제 테스트에서 표준 화질 60FPS, 인게임 4인 스쿼드 10분 대전 기준으로 Dirty 프레임 수 비율은 0.5%에 불과했다(193/38794). 결승권 마지막 1분에서도 그 비율은 0.58%까지밖에 오르지 않았다(22/3780).
다음 회차 예고: 《모바일 파이프라인 상수 소개와 구현 공유》
다음 회차에서는 GraphicsPipeline을 생성할 때 특정 상수 값을 지정할 수 있게 하여 렌더링 명령 파라미터를 최적화하는 기술 실천을 공유할 예정이다.
'TECH.ART.FLOW.IO' 카테고리의 다른 글
| [번역] 톤매핑만으로는 부족하다: 로컬 톤매핑 방안 정리 (0) | 2026.05.15 |
|---|---|
| [번역] Arknights: Endfield 캐릭터 카툰 렌더링을 0부터 모방·복각하기 (0) | 2026.05.11 |
| 번역[GDC2025 Core Concept] Decoding Light: Neural Compression of Global Illumination. (1) | 2026.05.08 |
| [번역] UE5 코드 한 줄도 안 고치고 카툰 렌더링 외곽선 구현하기 (2) | 2026.05.04 |
| [번역] Colored Shadow Penumbra (4) | 2026.05.04 |