TECHARTNOMAD | MAZELINE.TECH

TECH.ART.FLOW.IO

[번역] GDC 2025 — 《Marvel Rivals》 속 닥터 스트레인지 포털의 로우레벨 구현과 성능 최적화

jplee 2026. 8. 13. 23:46

역자의 말: 제가 넷이즈 광저우에서 근무 할 때 이미 몽환사업부에서 개발을 시작 했을 것 같은데요. 같은 건물에서 근무 했지만 사업부도 다르고 해서 이렇게 외부 발표자료로나 보게 되네요. 몽환사업부는 이 프로젝트 이전에는 언리얼엔진으로 게임을 쉬핑 해 본 적이 없는 사업부인데 잘 만들었네요. 몽환사업부는 넷이즈 전체 제1위 사업부인데요. NC 로 말하면 리니지 프렌차이즈를 끌고가는 원조 사업부? 같은 거라고 할까요? 15년 이상을 몽환서유 라는 중국 국민 게임으로 정말 어마어마한 돈을 벌어 넷이즈를 키운 공신중의 공신이기 때문입니다. 아무튼 가장 역사가 깊은 사업부라서 아마 넷이즈 내부 기술조직의 서포트를 엄청나게 잘 활용했을겁니다.


저자: wlxklyh

UE5 기술 교류방 참여 안내

언리얼 엔진 5의 그래픽 렌더링 기술에 관심이 있다면 UE5 기술 교류방에 참여해 주세요.

개인 WeChat wlxklyh를 추가한 뒤, 메시지에 “UE5”라고 남겨 주시면 교류방으로 초대해 드립니다.

기술 교류방에서는 다음과 같은 주제를 함께 나눌 수 있습니다.

  • 다른 UE 개발자들과 렌더링 기술 경험 공유
  • 그래픽 프로그래밍, 성능 최적화, 빌드 툴체인, 애니메이션 시스템 토론
  • 엔진 아키텍처, 기반 도구, 프로젝트 경험과 기술적 난제 공유

실시간 포털 렌더링 심층 분석: 《Marvel Rivals》 닥터 스트레인지 포털의 구현과 성능 최적화

원본 영상 정보

  • 제목: 【GDC 2025】Marvel Rivals — Creating a Real-Time Interactive Dr Strange's Portal
  • 재생 시간: 31분 15초
  • 출처: Bilibili 영상
  • 발표자: Zhang Tee-Yi · NetEase Games 그래픽 엔지니어

AI 생성 안내

이 글은 GDC 2025 기술 발표 영상을 바탕으로 AI가 정리한 콘텐츠입니다. 《Marvel Rivals》에 등장하는 닥터 스트레인지 포털의 실시간 렌더링 구현, 성능 최적화 전략, 멀티 뷰포트 렌더링 아키텍처를 다룹니다. 원 발표의 기술적 깊이는 최대한 유지하면서, 관련 원리와 실무적인 권장 사항을 함께 보충했습니다.

들어가며: 포털 렌더링이라는 기술적 난제

현대 게임 개발에서 실시간 포털 렌더링은 여전히 까다로운 기술 과제입니다. 언리얼 엔진으로 개발된 멀티플레이 경쟁 게임 《Marvel Rivals》는 닥터 스트레인지의 포털 능력을 핵심 플레이 메커니즘 가운데 하나로 구현했습니다. 플레이어가 맵의 다른 지점으로 빠르게 이동할 수 있을 뿐 아니라, 포털 너머의 공간을 실시간으로 보여 줍니다. 마치 다른 장소를 비추는 실시간 모니터와도 같습니다.

이 기능은 게임 출시 당시 중요한 셀링 포인트였고, 그만큼 렌더링 성능을 확보하는 일이 무엇보다 중요했습니다.

Screenshot 1

핵심 질문은 간단합니다. 시각적 품질을 유지하면서도 서로 다른 여러 시점의 장면을 감당 가능한 비용으로 실시간 렌더링하려면 어떻게 해야 할까?

전통적인 Scene Capture 방식은 구현하기 쉽지만, 뷰가 늘어날수록 비용이 급격히 커집니다. 이 글에서는 NetEase Games 팀이 멀티 뷰포트(Multi-Viewport) 아키텍처를 활용해 뛰어난 화면 품질을 유지하면서 포털 렌더링 성능을 50% 이상 끌어올린 과정을 깊이 살펴봅니다.

1부: Scene Capture를 이용한 전통적인 구현

Scene Capture 2D 컴포넌트의 동작 원리

언리얼 엔진에는 포털 효과를 구현할 때 가장 먼저 떠올릴 수 있는 Scene Capture 2D 컴포넌트가 있습니다. Scene Capture는 본질적으로 장면 속 원하는 위치에서 렌더링 결과를 캡처하는 가상 카메라입니다.

Screenshot 2

Scene Capture의 장점은 분명합니다.

  1. 바로 사용할 수 있다: 엔진 내장 기능이라 문서와 튜토리얼이 잘 갖춰져 있습니다.
  2. 렌더링 파이프라인이 일관적이다: 메인 뷰포트와 동일한 파이프라인을 사용하므로 화면 품질을 맞추기 쉽습니다.
  3. 프로토타입 제작이 빠르다: 핵심 기능만이라면 몇 분 안에도 구성할 수 있습니다.

데모 장면의 왼쪽 평면에는 Scene Capture 컴포넌트가 캡처한 레벨이 표시됩니다. 이 컴포넌트만으로도 기본적인 포털 효과는 어렵지 않게 만들 수 있습니다.

가상 카메라 위치 계산

포털 내부가 올바른 원근으로 보이게 하려면 먼저 가상 카메라의 위치를 구해야 합니다. 두 개의 포털이 배치된 장면이라면 계산 과정은 다음과 같습니다.

Screenshot 3

플레이어가 왼쪽 포털에 접근하는 상황을 위에서 내려다보면 다음 순서로 이해할 수 있습니다.

  1. 메인 카메라와 왼쪽 포털 사이의 상대 벡터를 계산합니다.
  2. 두 포털의 위치와 방향을 기준으로 이 벡터를 공간 변환합니다.
  3. 변환된 벡터를 이용해 왼쪽 포털이 캡처해야 할 가상 카메라 위치를 얻습니다.

이 과정에는 좌표 공간 변환이 필요하며, 포털의 회전·스케일·이동을 모두 고려해야 합니다. 수식의 의미를 단순화하면 다음과 같습니다.

// 의사 코드
FVector CameraOffset = MainCamera.Position - PortalA.Position;
FVector TransformedOffset = PortalB.Transform.TransformVector(
    PortalA.Transform.InverseTransformVector(CameraOffset)
);
FVector CapturePosition = PortalB.Position + TransformedOffset;

클립 플레인이 필요한 이유

카메라를 이동하거나 회전하면 Scene Capture가 벽 뒤쪽처럼 원래 보여서는 안 되는 지오메트리까지 포착하는 문제가 생길 수 있습니다. 가상 카메라가 뒤로 이동하면서 실제 구조물 안쪽으로 들어갈 수 있기 때문입니다.

Screenshot 4

해결책은 Scene Capture의 Clip Plane 속성을 활성화하는 것입니다. 클립 플레인은 월드 공간에 평면 하나를 정의하고, 어느 쪽의 지오메트리를 제거할지 결정합니다.

Screenshot 5

이 장면에서는 반대편 포털에 해당하는 월드 공간 평면을 클립 플레인으로 설정합니다. 셰이더는 시스템 값 SV_ClipDistance를 이용해 픽셀 단위로 정확하게 제거합니다. 덕분에 클립 플레인 바깥쪽의 지오메트리가 사라지고, 잘못된 물체가 비치는 현상을 막을 수 있습니다.

클립 플레인과 니어 플레인의 차이

  • 니어 플레인(Near Plane): 카메라 전방 축에 수직이며, 카메라와 함께 움직입니다.
  • 클립 플레인(Clip Plane): 고정된 월드 공간 평면을 기준으로 동작합니다.

SV_ClipDistance 사용은 GPU 성능에 어느 정도 부담을 줍니다. 하지만 올바른 시각 결과를 얻기 위해서는 감수해야 하는 비용입니다.

드러난 성능 병목

언리얼 엔진이 포털 렌더링에 필요한 핵심 도구를 이미 제공하고 있다고 해서 모든 문제가 해결되는 것은 아닙니다. 흔히 말하듯, 공짜가 때로는 가장 비쌉니다. 실제 게임에 포털을 통합하자 심각한 성능 저하가 곧바로 드러났습니다.

Screenshot 6

프로파일링 결과는 다음과 같았습니다.

  1. 렌더링 시간 증가: 포털이 하나 늘어날 때마다 사실상 별도의 전체 렌더링이 추가됩니다.
  2. 계단식 비용 상승: 렌더링 시간이 단계적으로 크게 뛰는 패턴이 나타납니다.
  3. 기준 데이터: 테스트 장면에서 두 포털과 메인 뷰를 합친 총 렌더링 시간은 약 26ms로, 기준 프레임의 약 3배에 달했습니다.

Screenshot 7

GPU 분석을 보면 문제의 뿌리가 더 선명해집니다. 한 프레임에서 서로 다른 세 번의 셰이딩 처리가 순차적으로 실행되고, 각 작업은 앞 작업이 끝날 때까지 기다려야 합니다. 그 사이 GPU에는 CPU의 다음 명령을 기다리는 유휴 구간이 길게 생깁니다.

CPU 바운드 상황의 특징

  • 렌더링 파이프라인이 직렬로 실행됩니다.
  • GPU가 CPU 스케줄링을 기다리며 쉬는 시간이 늘어납니다.
  • 각 뷰의 렌더링을 효율적으로 병렬화하기 어렵습니다.

명백한 CPU 병목입니다. 원인은 렌더링 파이프라인의 직렬 실행 구조에 있으므로, 작은 부분 최적화만으로는 해결하기 어렵습니다. 아키텍처 자체를 다시 설계해야 했습니다.

2부: 멀티 뷰포트 아키텍처를 이용한 돌파구

분할 화면에서 얻은 힌트

팀이 “뷰 하나당 약 10ms의 비용은 피할 수 없다”는 결론을 거의 받아들이려던 순간, 중요한 질문 하나가 떠올랐습니다.

언리얼 엔진의 분할 화면(Split Screen)은 어떻게 두 개의 뷰를 동시에 렌더링하면서도 성능이 무너지지 않는 걸까?

Screenshot 8

실마리는 블루프린트 함수 Create Local Player였습니다. 로컬 플레이어를 하나 추가하면 분할 화면 렌더링이 자동으로 활성화되고, 서로 다른 카메라로 각기 다른 시점을 그릴 수 있습니다.

Screenshot 9

프로파일링 결과는 결정적이었습니다. 서로 분리된 렌더링 프로세스와 달리, Create Local Player를 사용하면 두 뷰가 하나의 작업 흐름으로 묶입니다. 프레임당 렌더링 시간은 약 17ms에서 11ms로 크게 줄었습니다.

성능 향상의 본질적인 이유

  • 전통적인 Scene Capture: 직렬 실행. N개의 뷰는 N번의 완전한 렌더링 파이프라인에 가깝습니다.
  • Multi-Viewport: 여러 뷰를 한꺼번에 처리. N개의 뷰 비용이 대략 1.X회의 파이프라인 수준으로 줄어듭니다.

Multi-Viewport 아키텍처의 원리

Create Local Player는 언리얼 엔진의 네이티브 멀티 뷰 아키텍처를 사용합니다. 엔진 소스에서는 다음과 같은 for 루프 패턴을 확인할 수 있으며, 이것이 성능 개선의 핵심입니다.

Screenshot 10

// 언리얼 엔진 멀티 뷰 렌더링의 단순화된 흐름
for (FSceneView View : Views)
{
    // 지오메트리 제출 단계
    SubmitGeometry(View);
}

// 모든 뷰를 대상으로 통합 셰이딩
PerformDeferredShading(AllViews);

for (FSceneView View : Views)
{
    // 후처리 단계
    PostProcess(View);
}

이 구조의 장점은 세 가지입니다.

  1. 지오메트리를 묶어서 제출하므로 CPU와 GPU 사이의 통신 비용을 줄일 수 있습니다.
  2. 셰이딩 계산을 통합해 GPU의 병렬 처리 능력을 더 충분히 활용할 수 있습니다.
  3. 상태 전환 횟수가 줄어 드라이버 레벨의 오버헤드도 감소합니다.

여기서 중요한 것은 이 방식이 왜 시간을 절약하는지 이론적으로 끝까지 파고드는 것이 아니라, 그 원리를 실제 포털에 어떻게 적용하느냐입니다.

렌더 타깃 레이아웃 재설계

Create Local Player를 그대로 사용하면 화면이 둘로 나뉘지만, 우리가 원하는 포털 형태와는 다릅니다. 그래서 렌더 타깃의 레이아웃을 새로 설계했습니다.

Screenshot 11

레이아웃 전략

  1. 메인 뷰는 그대로 유지합니다. 기존 렌더 타깃 영역 전체를 계속 사용합니다.
  2. 렌더 타깃을 세로 방향으로 약 25% 확장합니다.
  3. 추가로 확보한 공간에 포털 뷰를 렌더링합니다.

Screenshot 12

디퍼드 렌더링 파이프라인의 마지막 단계에서 포털 화면을 추가 렌더 타깃으로 복사합니다. 다음 프레임에는 머티리얼이 이 버퍼를 샘플링해 포털 메시 위에 표시합니다.

Screenshot 13

첫 번째 최적화의 성과와 남은 문제

기본적인 변경을 적용한 뒤 실제 게임에서 성능을 측정한 결과는 다음과 같습니다.

Screenshot 14

 

  • 포털 없음: 약 120 FPS
  • Scene Capture 방식: 약 40 FPS · 성능 66% 하락
  • Multi-Viewport 방식: 약 80 FPS · 성능 33% 하락

Screenshot 15

언뜻 보면 충분히 큰 개선입니다. 하지만 문제는 아직 끝나지 않았습니다. 프레임을 30 FPS로 제한하고 화면을 움직여 보면 몇 가지 시각적 결함이 눈에 띕니다.

Screenshot 16

  1. 눈에 띄는 지연: 포털 속 이미지는 이전 프레임의 결과라 카메라를 따라오는 데 지연이 생깁니다.
  2. Lumen 근거리 AO의 검은 얼룩: 움직일 때 특히 두드러지고, 정지하면 안티앨리어싱 누적으로 차츰 완화됩니다.
  3. 고스팅: 최종 컬러 텍스처만 샘플링하기 때문에 안티앨리어싱에 필요한 깊이와 속도 정보가 없습니다.

Screenshot 17

복사 방식의 한계

  • 한 프레임 지연으로 반응성이 떨어집니다.
  • 움직일 때 고스팅 아티팩트가 발생합니다.
  • 렌더 타깃 크기를 확장하면 PlayStation이나 Xbox 같은 콘솔에서 메모리 한계를 넘을 수 있습니다.
  • GBuffer 정보가 부족해 후처리 품질이 떨어집니다.

결국 반드시 해결해야 할 핵심 문제가 하나 남았습니다.

3부: 깊이 버퍼 병합과 스텐실 프레임워크

메인 화면에 직접 렌더링하기

Multi-Viewport가 CPU 병목을 완화한다는 사실은 이미 확인했습니다. 그렇다면 다음 단계는 분명합니다. 포털 뷰를 별도 텍스처에 복사하지 말고, 메인 화면에 직접 통합 렌더링하는 것입니다.

Screenshot 18

뷰를 하나로 합치기 위해 다음 요소를 사용합니다.

  • 깊이 버퍼(Depth Buffer)
  • 포털 마스크(Portal Mask)
  • 스텐실 버퍼(Stencil Buffer)
  • 시저 렉트(Scissor Rectangle)

포털 마스크 생성

가장 먼저 포털 마스크가 필요합니다. 크기가 다른 두 포털이 있는 장면을 예로 들어 보겠습니다.

Screenshot 19

모든 장면은 Pre-Pass, 즉 Depth Pre-Pass에서 시작합니다. 언리얼 엔진의 디퍼드 렌더링 파이프라인은 불투명 오브젝트를 먼저 그려 깊이 맵을 만들고, 이후 단계에서 깊이 컬링에 사용합니다.

Screenshot 20

마스크 생성 과정은 다음과 같습니다.

  1. 첫 번째 드로우: 모든 포털 메시를 일반 메시처럼 처리해 메인 화면의 깊이 정보를 얻습니다.
  2. 두 번째 드로우: 포털 메시를 다시 그리되 깊이 테스트를 Equal로 바꾸고, 각 포털에 서로 다른 스텐실 값을 기록합니다.

Screenshot 21

이렇게 깊이-스텐실 버퍼가 만들어집니다. Pre-Pass에서는 기본적으로 다른 스텐실 값을 기록하지 않기 때문에 포털이 아닌 영역의 스텐실 값은 모두 0, 즉 검은색으로 남습니다.

Screenshot 22

이 스텐실 영역을 별도의 8비트 부호 없는 정수 렌더 타깃에 복사해 백업하면 포털 마스크가 완성됩니다.

깊이 버퍼를 병합하는 과정

이제 중요한 질문은 이 포털 마스크를 어떻게 활용하느냐입니다. 메인 뷰의 Pre-Pass를 예로 들어 포털 단계를 통합하는 과정을 살펴보겠습니다.

Screenshot 23

1단계: 메인 장면 깊이 백업

먼저 메인 장면의 깊이 버퍼를 별도 리소스에 복사합니다. 이 리소스를 Portal Sync Depth라고 부릅니다.

2단계: 깊이 또는 스텐실 값 주입

각 뷰를 렌더링하기 전에 깊이-스텐실 렌더 타깃을 제한해야 합니다. 한 가지 방법은 렌더링할 영역의 스텐실 값을 0, 나머지 영역을 1로 만드는 것입니다. 다른 방법은 깊이 값을 직접 주입하는 것입니다. 언리얼 엔진의 Reversed-Z 기준에서 깊이 값 1은 카메라에 가장 가까운 위치를 뜻하므로, 이 값을 넣은 픽셀은 이후 지오메트리가 깊이 테스트를 통과하지 못합니다.

Screenshot 24

이 구현에서는 두 번째 방식, 즉 깊이 값 주입을 선택했습니다.

3단계: 포털 내부 렌더링

Screenshot 25

와이어프레임의 노란 선을 기준으로 보면 초록색 픽셀은 깊이 테스트를 통과한 영역이고, 빨간색 픽셀은 실패한 영역입니다. 포털 바깥에서는 깊이 컬링이 정상적으로 동작합니다. 이제 각 포털의 내용을 차례로 그릴 수 있습니다.

Screenshot 26

4단계: 포털 외부 깊이 복원

마지막에는 포털 바깥쪽에 주입했던 깊이 값을 제거해야 합니다. 앞에서 백업한 메인 뷰의 포털 깊이와 포털 마스크를 이용하면 나머지 영역을 원래대로 복원할 수 있습니다.

Screenshot 27

그 결과 포털의 깊이가 메인 뷰 깊이 맵 안으로 병합됩니다. 다른 포털도 같은 과정을 반복하면 됩니다.

Screenshot 28

이제 메인 화면과 포털 화면이 하나의 일관된 깊이 구조를 공유합니다.

스텐실 버퍼 적용 예시

다음은 포털 스텐실을 이용해 메인 뷰와 포털 뷰를 구분하는 간단한 예입니다.

Screenshot 29

메인 뷰의 GBuffer를 렌더링할 때는 포털 마스크가 렌더링하면 안 되는 픽셀을 스텐실 테스트로 제거합니다.

여기에서 사용하는 스텐실 값은 포털 인덱스가 아니라 특수 값 1입니다. 이 팀의 엔진에서는 Base Pass 단계에서 값 1을 예약해 두었고 다른 용도로 쓰지 않았기 때문입니다. 실제 적용 시에는 각자의 엔진 구조에 맞는 값을 선택하면 됩니다.

Screenshot 30

스텐실 값으로 메인 뷰의 GBuffer 렌더링 영역을 제한한 다음, 서로 다른 셰이딩 모델 ID를 이용해 스텐실 버퍼를 시각화할 수 있습니다.

이제 각 포털을 개별적으로 렌더링합니다. 메인 뷰에서 했던 것처럼 렌더링할 영역은 0, 그 밖의 영역은 1로 표시합니다.

Screenshot 31

포털 내부에 그려지는 오브젝트는 정해진 영역으로 제한됩니다. 포털 밖으로 벗어난 일부 빨간 픽셀은 스텐실 테스트에서 제거됩니다.

하드웨어 시저 영역 최적화

렌더링 효율을 한 단계 더 높이기 위해 C++ 코드에서 포털의 화면 공간 영역을 계산하고, 하드웨어 Scissor 영역을 설정했습니다.

Screenshot 32

점선 상자가 Scissor 영역입니다. 초록색 픽셀은 Scissor 안쪽, 분홍색 픽셀은 바깥쪽을 나타냅니다.

스텐실만으로도 이미 뛰어난 컬링 성능을 얻을 수 있었습니다. 최신 테스트에서는 Scissor가 주된 최적화라기보다 안전장치에 가까운 역할을 합니다.

통합 렌더링 프레임워크

스텐실 기반 프레임워크의 전체 흐름은 다음과 같습니다.

Screenshot 33

메인 뷰를 포함한 각 뷰마다 다음 작업을 반복합니다.

  1. 먼저 스텐실 값을 주입합니다.
  2. 해당 뷰의 내용을 그립니다.
  3. 마지막으로 스텐실 값을 지웁니다.

일부 후처리 효과에는 셰이더 앞부분에 다음과 같은 코드를 추가할 수 있습니다.

// 포털 마스크 샘플링
uint PortalMask = PortalMaskTexture.Load(int3(PixelPos.xy, 0)).r;

// 동적 분기로 현재 포털 영역인지 판별
if (PortalMask == CurrentPortalIndex)
{
    // 포털 내부 처리
}
else
{
    // 포털 외부 처리
}

동시에 View 구조체에 Portal View Index 멤버를 추가해 현재 처리 중인 포털을 식별합니다.

Exponential Height Fog 적용 사례

Exponential Height Fog처럼 세 뷰 모두에서 풀스크린으로 실행되는 효과에도 이 프레임워크를 적용할 수 있습니다.

Screenshot 34

위 이미지는 높이 안개를 적용하기 전의 상태입니다. 이후 작은 포털, 큰 포털, 메인 뷰(View 0)에 각기 다른 높이 안개를 적용합니다. 뷰마다 카메라 위치와 높이에 맞는 안개 파라미터를 독립적으로 계산할 수 있어 훨씬 자연스러운 결과를 얻습니다.

4부: 기능별 세부 최적화 전략

Lumen 글로벌 일루미네이션 최적화

첫 번째 대상은 Lumen Scene Lighting과 Mesh Cards입니다. 특히 멀리 있는 포털은 각 뷰의 Final Post Process Settings를 조정해 품질을 낮췄습니다.

Screenshot 35

조정할 수 있는 주요 속성은 다음과 같습니다.

  • LumenSceneLightingQuality: 장면 조명 품질
  • LumenSceneDetail: 장면 디테일 단계
  • LumenSceneViewDistance: 장면 가시 거리
  • LumenSurfaceCacheResolution: 서피스 캐시 해상도

더 자세한 내용은 언리얼 엔진 소스 코드에서 확인할 수 있습니다.

간격 업데이트 전략

장면의 조명이 급격하게 바뀌지 않는다면 Lumen 조명을 매 프레임 업데이트할 필요가 없습니다. 이 게임에서는 5~10프레임마다 한 번씩 실행하도록 조정했습니다.

Screenshot 36

PlayStation 5 측정 결과

  • 최적화 전: Lumen Scene Lighting의 GPU 실행 시간 약 0.5ms
  • 5프레임 간격 업데이트: 평균 GPU 시간 약 0.1ms

Screenshot 37

이 수치는 한 프레임의 비용을 단순히 10프레임에 나눠 표시한 것이 아닙니다. 실제 평균 실행 시간이 줄어든 결과입니다. 다만 장면 조명이 지나치게 오랫동안 갱신되지 않는 상황은 피해야 합니다.

동적 보정 방식

매 프레임 추가되는 Mesh Card 수를 감시해 업데이트 빈도를 동적으로 바꿉니다. 새로 추가된 카드 수가 임계값을 넘으면 간격 최적화를 잠시 끄고, 10~30프레임 동안 Lumen Scene Lighting을 연속 업데이트합니다.

// 의사 코드
if (AddedMeshCardsCount > Threshold)
{
    bForceUpdateLumen = true;
    ForceUpdateFrameCount = 30;
}

if (ForceUpdateFrameCount > 0)
{
    UpdateLumenEveryFrame();
    ForceUpdateFrameCount--;
}
else
{
    UpdateLumenWithInterval(5); // 5프레임마다 한 번 업데이트
}

여러 레벨에서 Lumen을 사용할 때 꽤 보편적으로 적용할 수 있는 최적화 방식입니다.

Lumen Screen Probe Gather 최적화

Lumen Screen Probe Gather는 GPU 주도형 알고리즘이기 때문에 Multi-Viewport에 비교적 쉽게 적용할 수 있습니다. 이런 계산 집약형 작업은 마스크 프레임워크를 이용해 필요한 영역에서만 프로브를 계산하면 됩니다.

Screenshot 38

RenderDoc 캡처의 중간 결과를 보면 Screen Probe Gather를 세 번 실행하더라도, 매번 해당 뷰의 영역 안에만 프로브가 배치됩니다. 각 뷰의 Lumen GI 계산 역시 정해진 범위로 제한되므로 불필요한 연산을 줄일 수 있습니다.

그림자 품질과 성능의 균형

포털 안쪽 장면의 시각적 일관성을 유지하려면 온전한 그림자 렌더링이 필요합니다. 다만 포털 뷰에는 메인 뷰보다 낮은 그림자 품질을 설정할 수 있습니다.

Screenshot 39

성능 모드나 낮은 사양의 하드웨어처럼 극단적인 상황에서는 타협도 필요합니다. 이 게임은 그런 경우 Lumen을 비활성화합니다.

Screenshot 40

두 모드의 이미지를 빠르게 번갈아 보면 차이가 눈에 띌 수 있습니다. 하지만 나란히 놓고 보면 생각보다 큰 차이를 느끼기 어렵습니다.

Screenshot 41

아트팀은 별도의 설정과 라이팅 기법을 활용해 성능 모드도 품질 모드에 가까워 보이도록 다듬었습니다.

동시에 표시하는 포털 수 제한

화면에 동시에 나타나는 포털 수에도 제한을 두었습니다. 올해 초 공개한 최신 섹터 맵에서는 어떤 순간에도 포털 하나만 화면에 표시되도록 했습니다.

Screenshot 42

우선순위 규칙은 단순합니다.

  • 플레이어가 현재 조준하고 있는 포털을 우선 렌더링합니다.
  • 나머지 포털은 비활성 상태로 유지합니다.

핵심 게임 경험은 유지하면서도 렌더링 부담을 크게 줄이는 현실적인 선택입니다.

실전 성능 데이터와 플랫폼별 비교

마지막으로 PlayStation 5에서 캡처한 결과를 살펴보겠습니다.

Screenshot 43

초기 Scene Capture 방식

  • 프레임 레이트가 120 FPS에서 16 FPS까지 하락
  • 약 87%의 성능 손실

개선된 Multi-Viewport 방식

  • 프레임 레이트 50% 이상 향상

Screenshot 44

렌더링 부하가 큰 스트리밍 장면에서 두 포털을 동시에 표시하고 PC, Xbox Series S, PlayStation 5의 프레임 레이트를 비교했습니다.

품질 모드 성능 비교

장면 상태  PC  Xbox Series S PS5
포털 없음 약 120 FPS 약 90 FPS 약 100 FPS
Scene Capture 약 40 FPS 약 30 FPS 약 35 FPS
Multi-Viewport 약 80 FPS 약 60 FPS 약 70 FPS

성능 모드는 기준 FPS 자체가 더 높고, 최적화 효과 역시 비슷하게 크게 나타났습니다.

기술 정리와 실무 권장 사항

핵심 기술 다시 보기

  • 1부에서는 Scene Capture 2D로 포털을 구현하는 기본 방식을 살펴보고, 실제 게임에 적용했을 때 발생하는 성능 병목을 확인했습니다.
  • 2부에서는 Multi-Viewport를 이용해 포털 렌더링을 메인 뷰의 작업 흐름에 통합하고, 아키텍처 수준에서 성능을 개선했습니다.
  • 3부에서는 깊이 버퍼 병합과 스텐실 마스크를 활용해 포털을 메인 화면에 직접 렌더링하는 방법을 다뤘습니다.
  • 4부에서는 Lumen, 그림자, 포털 수 제한 등 기능별 최적화 전략을 정리했습니다.

중요한 설계 결정

  • 포털 마스크 생성: 포털 메시를 다시 그려 마스크를 만들고, 하드웨어 스텐실 버퍼로 픽셀 단위 판정을 수행합니다.
  • 뷰 구분 방식
    • Base Pass 같은 지오메트리 렌더링 단계에서는 하드웨어 스텐실 버퍼를 사용합니다.
    • 후처리 단계에서는 소프트웨어 방식의 픽셀 샘플링을 사용합니다.
    • 깊이 테스트와 오클루전 컬링에는 깊이 맵 병합을 사용합니다.

렌더링 단계마다 성격이 다르기 때문에 하나의 방법으로 모든 문제를 해결하려 하기보다, 이미 존재하는 리소스와 하드웨어 기능을 적절히 조합해 포털 영역을 분리하는 것이 핵심입니다.

뷰 통합이 주는 이점

포털 뷰를 메인 렌더링에 통합하면 다음과 같은 효과를 단일 후처리 흐름 안에서 처리할 수 있습니다.

  • Bloom
  • Lens Flare
  • Tone Mapping
  • Eye Adaptation
  • Anti-Aliasing

성능이 좋아질 뿐 아니라, 모든 뷰의 시각적 일관성도 확보할 수 있습니다.

실무에서 기억할 점

  1. 점진적으로 최적화할 것: 처음에는 Scene Capture로 빠르게 프로토타입을 만들고, 병목이 분명해진 뒤 Multi-Viewport 리팩터링을 검토하는 편이 효율적입니다.
  2. 플랫폼별 설정을 준비할 것: 플랫폼과 그래픽 모드에 맞는 품질 단계를 별도로 마련해야 합니다.
  3. 동적 LOD를 활용할 것: 포털까지의 거리와 화면 점유율에 따라 렌더링 품질을 조절하면 비용을 더 줄일 수 있습니다.
  4. 지속적으로 측정할 것: 성능 모니터링 체계를 구축해 새로운 병목을 빠르게 발견하고 해결해야 합니다.

앞으로의 발전 가능성

현재 방식만으로도 성능은 크게 좋아졌지만, 더 발전시킬 여지는 남아 있습니다.

  1. 재귀 포털 지원: 현재는 포털끼리 마주 볼 때 발생하는 무한 반사 형태를 지원하지 않습니다. 제한된 깊이의 재귀 렌더링을 검토할 수 있습니다.
  2. 하드웨어 레이 트레이싱 통합: DXR 또는 Vulkan Ray Tracing을 활용해 포털 내부의 반사와 글로벌 일루미네이션을 가속할 수 있습니다.
  3. 가변 해상도 렌더링: 포털 뷰를 낮은 해상도로 렌더링한 뒤 업샘플링으로 디테일을 복원할 수 있습니다.
  4. 비동기 컴퓨트 최적화: 일부 Lumen 연산을 비동기 큐로 옮겨 병렬성을 더 높일 수 있습니다.

마치며

실시간 포털 렌더링은 화면 품질, 성능, 메모리 사용량 사이에서 균형을 찾아야 하는 복합적인 문제입니다. 《Marvel Rivals》의 기술팀은 엔진 아키텍처를 깊이 분석한 끝에 Multi-Viewport라는 돌파구를 찾았고, 최종적으로 50%가 넘는 성능 향상을 이끌어 냈습니다.

이 사례가 다시 한번 보여 주는 사실은 분명합니다. 성능 최적화는 작은 부분을 조금씩 다듬는 작업만을 뜻하지 않습니다. 때로는 문제를 아키텍처 차원에서 다시 바라봐야 합니다. 엔진 내부 동작을 깊이 이해할수록, 예상보다 훨씬 큰 개선의 기회를 발견할 수 있습니다.

이 글의 기술적 세부 내용과 최적화 전략이 여러분의 포털 시스템을 설계하는 데 도움이 되길 바랍니다. 그래픽 렌더링 기술은 결국 경험을 나누고 서로 검증하는 과정 속에서 발전합니다. 앞으로도 더 많은 실시간 렌더링 사례와 새로운 해법을 만나게 되기를 기대합니다.

함께 보면 좋은 발표

《Marvel Rivals》의 기술 구현에 관심이 있다면, 팀의 다른 GDC 발표도 함께 살펴볼 만합니다. 언리얼 엔진의 KL 시스템을 실제 게임에 적용한 사례 등이 좋은 참고가 됩니다.

기술 참고 자료

  • Unreal Engine 공식 문서: Scene Capture 컴포넌트
  • GDC Vault: 실시간 렌더링 기술 발표 모음
  • GPU 프로파일링 모범 사례

 


원문
(80 封私信 / 48 条消息) GDC2025——Marvel Rivals中奇异博士传送门的底层实现与性能优化 - 知乎