포트나이트 배틀로얄 챕터 4의 버추얼 섀도 맵

Andrew Lauritzen, 시니어 렌더링 프로그래머, Ola Olsson, 시니어 렌더링 엔지니어 |
2023년 1월 26일
안녕하세요, 저희는 앤드류 로리첸(Andrew Lauritzen)과 올라 올슨(Ola Olsson)입니다. 현재 언리얼 엔진 5 섀도잉을 주로 맡고 있는 렌더링 엔지니어이며, 언리얼 엔진 5 작업을 시작한 이래 버추얼 섀도 맵(VSM, Virtual Shadow Map)에 초점을 맞추어 왔습니다. 버추얼 섀도 맵은 나나이트의 가상화 지오메트리와 잘 어울리도록, 그리고 카메라 근처의 자그마한 지오메트리 디테일부터 지평선 너머까지 정확한 섀도를 효율적으로 렌더링하도록 설계되었습니다.

이번 블로그에서는 버추얼 섀도 맵이 포트나이트 배틀로얄 챕터 4에서 사용된 방식에 대해 자세히 다루면서, 특히 최근 이루어진 기술적 향상과 콘텐츠별 고려사항에 초점을 맞추어 보겠습니다. VSM은 특히 나나이트를 염두에 두고 나나이트 래스터화 프로세스를 긴밀히 통합하도록 설계되었습니다. 섀도 최적화와 나나이트 퍼포먼스는 대부분의 경우 직결되어 있습니다. 따라서 포트나이트 배틀로얄 챕터 4의 나나이트 블로그를 먼저 읽고 이 블로그를 읽는 것을 권장합니다. 해당 블로그에서 언급된 기술 다수는 버추얼 섀도 맵만큼, 어떤 경우에는 그 이상으로 중요할 수 있습니다.

챕터 4에서 나나이트가 많이 쓰였다는 점을 감안하면 버추얼 섀도 맵은 자연스러운 선택입니다. 기존 섀도 맵과 비교했을 때 둘 다 더 나은 퍼포먼스와 퀄리티를 보여주기 때문이죠. 레이 트레이스드 섀도는 포트나이트의 강렬한 다이내믹 디포메이션과 애니메이션을 묘사하고자 가속 구조체를 강제로 리빌드할 때 퍼포먼스가 썩 좋지 않으므로 아직 적합하지 않습니다. 또한 레이 트레이스드 섀도는 나나이트 지오메트리의 덜 디테일한 버전을 사용하기 때문에 일부 이펙트에는 적합할 수 있으나, 다이렉트 섀도잉에 적용될 때는 자세한 디테일이 부족합니다.
챕터 4에서의 섀도잉에는 퍼포먼스와 퀄리티 외에도 몇 가지 구체적인 목표를 설정해 두었으며 이어지는 내용에서 다루어 보겠습니다.


태양 섀도(디렉셔널 라이트)

포트나이트는 주로 야외 배경인 게임이기 때문에 플레이어가 보게 될 그림자 대부분은 햇빛으로 인한 것입니다. 햇빛은 가장 까다로운 라이트 중 하나이기도 한데, 이상적으로는 플레이어에게서 몇 센티미터 떨어진 곳에서부터 지평선에 이르기까지 모든 그림자가 시각적으로 일관되게 보여야 합니다. 포트나이트 배틀로얄에서 이러한 스케일의 차이는 그냥 존재하는 수준이 아니라 게임 시작 시 하늘에서 다이빙하는 시퀀스부터 그대로 드러납니다.

원래 포트나이트는 다양한 섀도 기법을 사용하여 퍼포먼스 밸런스를 맞추면서 모든 경우를 처리하였습니다. 플레이어 근처에서는 기존 섀도 맵 캐스케이드가 몇 가지 나타납니다. 좀 더 멀리 떨어지면 디스턴스 필드 섀도와, 맵의 전부까지는 아니어도 대부분을 덮는 단일 '파' 캐스케이드가 혼합되어 있습니다. 플레이어 캐릭터는 전용 오브젝트별 섀도 맵을 갖습니다. 스크린 스페이스 컨택트 섀도는 이 모든 것 위에 레이어링되어 저해상도 테크닉으로 인해 누락된 디테일을 복구하고 원거리에서 누락된 섀도를 채웁니다.

과거에는 이러한 섀도 테크닉 혼용이 꽤 잘 작동했지만, 먼 거리에서 저해상도의 흐릿한 섀도만 생성할 수 있었으며 테크닉이 전환되는 경계에서 차이점이 눈에 띌 때가 많았습니다. 나나이트를 활용하여 누릴 수 있는 가장 큰 비주얼 이점은 레벨 오브 디테일 전환에 제공되는 템포럴 안정성으로부터 옵니다. 템포럴 안정성을 약화시키는 대표적인 상황은 섀도가 사라지거나, 갑자기 출현하거나, 서로 다른 거리에서 테크닉이 전환되는 경우입니다.

버추얼 섀도 맵은 이 모든 테크닉을 단일 통합 패스로 대체합니다.

버추얼 섀도 맵 캐싱 고려사항

버추얼 섀도 맵은 퀄리티 요구사항을 충족할 수 있으나, 과거 나나이트 세계의 루멘매트릭스 어웨이큰스: 언리얼 엔진 5 익스피어리언스 데모에서는 좋은 퍼포먼스를 내고자 캐싱 섀도 맵 페이지에 크게 의존하였습니다. 포트나이트에서는 이전 데모보다 더 높은 퍼포먼스 레벨을 목표로 할 뿐만 아니라 섀도 맵 캐싱 기능을 크게 약화시키는 두 가지 제약에도 주목하고 있는데, 바로 상당량의 애니메이팅된 디포메이션(주로 나무)과 계속해서 움직이는 태양입니다.

처음에는 '최적화된 WPO' 플래그(나나이트 블로그에서 다룬 내용)를 준수하며 애니메이팅된 지오메트리의 무효화를 줄이는 데 도움이 될 향상안 다수를 구현하였습니다. 효과가 있었지만 저희가 목표로 하는 퍼포먼스 기준치를 만족하지는 못했습니다.

몇 가지 간단한 우선순위 체계로 무효화를 직접 제한하려 시도해 보았으나, 이 경우 페이지 경계에 너무 많은 그래픽 오류가 발생했습니다. 이러한 체계는 원거리 지오메트리 렌더링 비용이 제일 많이 드는 기존 섀도 맵에서는 잘 작동하지만, 나나이트와 버추얼 섀도 맵은 화면상 픽셀에 비용을 일치시키는 게 더 좋습니다. 이렇게 했을 때 디스턴트 섀도의 비용이 비교적 저렴해지지만, 실제로 나무 가까이 다가가 위를 올려다 볼 때 지나친 오버드로로 인해 섀도 페이지의 효율성이 감소하고 나나이트 퍼포먼스도 저하될 만큼 지오메트리의 일관성이 줄어드는 최악의 상황이 발생합니다.
단순히 섀도 페이지 업데이트를 제한하거나 건너뛰면 카메라 근처에 눈에 잘 띄는 그리팩 오류가 발생합니다. 저희는 '베이스 포즈'를 사용해 일부 오브젝트를 섀도 페이지 캐시에 그린 다음, 섀도 룩업을 해당 포즈에 다시 투영하는 실험을 수행했습니다. 그 결과 마치 구운 라이팅에서처럼 그림자가 표면에 딱 붙은 채 애니메이팅된 오브젝트 주변을 따라다니는 효과가 나타났습니다. 안타깝게도 나뭇잎 그림자가 다른 나뭇잎에 드리운 셀프 섀도잉 부분을 다른 오브젝트가 나무에 드리운 섀도로부터 쉽게 분리할 수 있는 방법이 없었기 때문에, 실제 결과물은 좋지 못했습니다.

두 번째 제약 사항은 더 큰 문제가 있었습니다. 포트나이트에서는 태양의 방향이 계속해서 변화하며 하루의 시간 흐름을 만들어냅니다. 완전히 정확하게 하려면 라이트 방향이 변경될 때마다 캐시된 섀도 맵 데이터를 전부 버려야 하지만, 태양이 그렇게 빠르게 움직이지 않는 만큼 이 부분에서는 '요령'을 적용하는 게 상당히 일반적입니다. 하지만 버추얼 섀도 맵에는 이걸 더 어렵게 만드는 요인이 몇 가지 있습니다.

우선 섀도 데이터 회전만이 아니라 페이지가 떨어지는 부분의 전체 파라미터화가 문제입니다. 이 이펙트는 카메라 근처 페이지에서 보기에 태양이 눈에 띄게 느리게 움직이는 경우에도 상당히 두드러질 수 있습니다.
포트나이트에서 태양의 움직임은 프레임마다 눈에 띄는 섀도 페이지 테이블 변경을 유발합니다.
즉 최소 한 프레임에서 다음 프레임까지 캐시 데이터를 재투영해야 하며, 애초에 처음부터 추가 오버헤드를 추가하고 캐싱으로 절감한 만큼을 소모해야 합니다. 고밀도의 섀도 맵 재투영은 비교적 직관적입니다. 경계에서 데이터가 일부 손실되기는 하지만 일반적으로 사소한 문제들은 비교적 흐릿해진 섀도 출력에 의해 가려질 수 있습니다.

안타깝게도 새 페이지를 재구성하려면 버추얼 섀도 맵에서 다루는 모든 소스 페이지가 이전 프레임에 매핑되었어야 합니다. 그렇지 않으면 부분적으로 유효하지 않은 섀도 페이지를 캐싱하게 됩니다. VSM은 분산을 통해 효율성이 한층 높아지며 밀도가 높은 섀도 데이터에서는 눈에 확 띄는 '구멍'이 생깁니다. 이 경우 재사용 가능한 캐시된 페이지 양이 더욱 줄어듭니다.

또한 VSM은 일반적으로 해상도가 더 높고 기존 섀도 맵보다 더 선명한 필터링을 사용하기 때문에 각종 문제와 부정확성이 시각적으로 더 두드러지고 광범위한 블러링으로 가려질 가능성도 적습니다. 마지막으로 무효화에서 발생할 수 있는 최악의 경우는 이런 재투영에서도 똑같습니다. 나무처럼 노이즈가 많은 오브젝트를 살펴보면, 데이터에 구멍이 너무 많아서 재구성 가능한 페이지가 거의 없습니다.

이런 문제들과 나쁜 사례가 전반적으로 발생함에 따라 포트나이트의 태양 그림자 전략이 완전히 뒤바뀌게 되었습니다.

캐싱되지 않은 태양 그림자

포트나이트에서 캐싱이 불가능한 경우를 완전히 피할 수는 없으니, 이런 경우 퍼포먼스 예산에 맞추어야 합니다. 여기에 60fps 목표도 함께 달성하고자, 태양 그림자의 실질적인 해상도 목표를 이전 데모의 거의 절반 수준으로 낮추었습니다. 이 방식은 확실히 시각적으로 큰 영향을 주지만, 섀도 자체는 이전 비교 데모에서 보았듯 여전히 기존 테크닉에 비해 훨씬 더 높은 해상도가 됩니다. 또한 디렉셔널 라이트 페이지는 절대 캐싱하지 않을 거라고 가정하여 기록 및 무효 오버헤드를 줄이기 위해 (r.Shadow.Virtual.Cache.ForceInvalidateDirectional) 제어를 추가하였습니다.

이런 결정에 의한 장단점은 게임에 따라 달라집니다. 섀도 맵 캐싱을 포기하고 섀도 해상도를 낮추면 확실한 시각적 영향이 있기 때문에 다른 게임에서는 최적의 결정이 아닐 수 있습니다. 그러나 포트나이트에서는 60fps의 디렉셔널 라이트 섀도 캐싱이 없더라도 이전 솔루션보다 확실히 눈에 띄게 향상되었기 때문에 저희가 달성한 퀄리티 수준에 만족합니다.

비나나이트 지오메트리

태양에 대한 캐싱 추적을 중단하기로 한 상황에서는 섀도 맵으로의 근본적인 렌더링 퍼포먼스 자체가 제일 중시됩니다. 우수한 VSM 렌더링 퍼포먼스를 달성하기 위해 가장 중요한 첫 단계는 모든 요소를 나나이트로 만드는 것입니다. 비나나이트 오브젝트는 특히 폴리곤 수가 많거나, 물리적으로 크거나, 많은 버추얼 섀도 맵 페이지가 오버랩될 경우 심각한 퍼포먼스 문제를 일으킬 수 있습니다.

포트나이트에는 콘텐츠가 대단히 많기 때문에, 최악의 문제 요인을 찾고자 퀵 더티 디버그 출력을 만들었습니다. r.Shadow.Virtual.NonNanite.NumPageAreaDiagSlots -1로 설정하면 게임은 섀도 맵 다수를 덮은 비나나이트 인스턴스를 식별하는 디버그 텍스트를 출력합니다.
처음으로 마주한 가장 큰 문제 요인 중 하나는 랜드스케이프였습니다. 그래서 주로 버추얼 섀도 맵 퍼포먼스를 향상시킬 목적으로 간단한 나나이트 랜드스케이프 지원을 추가하여 문제를 효과적으로 제거했습니다.

포트나이트 배틀로얄 챕터 4에서는 방대한 지오메트리 대부분을 나나이트로 변환하여 섀도 퍼포먼스를 크게 향상할 수 있었습니다. 플레이어 모델을 비롯해 여전히 비나나이트 섀도가 드리운 오브젝트가 남아 있기는 하지만, 그 수가 적고 크기도 작아 일반적으로 퍼포먼스 문제를 일으키지 않습니다.

버추얼 섀도 맵은 또한 다양한 볼류메트릭 이펙트를 지원하고자 전체 프러스텀을 커버하는 초저해상도 맵 '저품질 페이지'를 유지합니다. 나나이트의 놀라운 LOD 덕분에 저품질 페이지 렌더링에 높은 효율성을 선보입니다. 하지만 비나나이트 지오메트리는 이전 버전에서 대규모의 변수 오버헤드를 유발했는데, 주로 쓸모없는 버텍스 프로세싱으로 인한 것이었습니다. 이 문제를 완화하고자 소형 오브젝트 필터링을 저품질 페이지에 추가했으며, 덕분에 해당 기능이 적용된 상태로 포트나이트를 출시할 수 있었습니다. 이 기능은 언리얼 엔진 5.1에도 기본적으로 적용됩니다.

폴리지

향상된 폴리지는 포트나이트 배틀로얄 챕터 4의 주요 비주얼 목표 중 하나인 동시에 주요 퍼포먼스 우려사항 중 하나이기도 했습니다.

캐시되지 않은 섀도 렌더링 퍼포먼스를 최적화하면 메인 뷰에서 동일한 요소 다수가 완화됩니다. 그 내용은 나나이트 블로그에서 자세히 확인할 수 있습니다. 섀도 퍼포먼스에 가장 큰 영향을 준 부분은 바로 알파 테스트를 제거하고 포트나이트에서는 대부분 사전 연산되는 월드 포지션 오프셋 함수의 비용을 최대한 절감한 것입니다. 이처럼 매우 디테일한 나나이트 메시에서는 이미 해당 기능의 비용이 높지만, 메시 클러스터가 다수의 섀도 클립맵 레벨에 걸쳐 있을 경우 메시 클러스터를 몇 번 래스터화해야 할 수도 있습니다.

메인 뷰와의 일관성을 유지하기 위한 일환으로 월드 포지션 오프셋 거리 컬링을 주요 카메라 위치에 상대적으로 섀도 패스에 구현했는데, 덕분에 라이트 위치에 기반해 컬링할 때보다 약간의 퍼포먼스 향상이 있었습니다.

포트나이트는 챕터 4 이전에 이미 '섀도 프록시' 시스템을 사용했습니다. 초기에는 섀도 퍼포먼스 예산으로 섀도 패스 내의 폴리곤이 30만 개 이상인 나무 메시 전체를 처리할 수 있을지 불확실했습니다. 섀도는 일반적으로 주요 뷰와 비슷하거나 경우에 따라 더 많은 픽셀 수를 렌더링함에도 불구하고 더 적은 프레임 예산이 할당되기 때문입니다. 섀도 프록시를 구현하려면 나무 액터 하나에 스태틱 메시 컴포넌트 두 개를 구성합니다. 하나는 '그림자 드리우기'가 비활성화된 메인 뷰 용, 다른 하나는 '숨겨진 섀도 드리우기'가 활성화된 섀도 프록시용입니다.

챕터 4의 경우 섀도 프록시 메시는 여전히 꽤 복잡합니다. 보통 60만 개 이상의 트라이앵글이 사용됩니다.
(왼쪽) 기본 나무 메시(폴리곤 30만 개 이상) | (오른쪽) 나무 섀도 프록시 메시(폴리곤 60만 개 이상)
디테일을 너무 저하시키면 나무 윗부분의 라이팅 깊이감이 크게 감소하므로, 프록시는 섀도가 드리운 나무에 시각적 영향을 최소화하도록 조정되었습니다. 적용 시 섀도 프록시는 디테일을 약간 잃긴 하지만, 두 이미지를 직접 비교하지 않는 한 딱히 눈에 띌 정도는 아닙니다.
(왼쪽) 섀도 프록시 메시를 갖춘 나무 | (오른쪽) 섀도 프록시 메시가 없는 나무
나나이트의 '영역 보존' 옵션이 추가되기 전에, 그리고 나나이트의 프로그래밍 가능 래스터화 최적화 다수가 구현되기 전에 이미 섀도 프록시를 평가했다는 점은 짚고 넘어갈 만한 부분입니다. 프로세스 후반에는 꼼꼼히 재평가할 시간이 없었습니다. 게다가 섀도 프록시 시스템은 포트나이트에 이미 존재했으며 비나나이트 플랫폼에도 계속 필요할 것입니다.

그렇지만 앞으로의 퍼포먼스에서 섀도 프록시가 필수적일 거라고는 완전히 자신하지 않습니다. 기존의 인식과는 달리, 나나이트는 여전히 해당 범위 내 두 메시에 대해 동일한 트라이앵글 밀도를 목표로 하기 때문에 원거리 또는 중간 거리에 있는 폴리지의 퍼포먼스에는 획기적인 차이를 만들어 내지 않습니다. 나나이트 섀도 프록시가 유일하게 중요할 때는 나무가 카메라에 매우 가까운 경우이며, 이때 프록시는 섀도 패스에서 렌더링될 지오메트리의 디테일 레벨을 살짝 낮춥니다.

챕터 4 이후에 수행한 개념 증명 작업에 기반하여 더 이상 아티스트가 생성하는 섀도 프록시 메시는 필요하지 않다고 자신합니다. 유사한 퍼포먼스와 퀄리티를 달성하는 데 가장 필요한 것은 이런 메시에서 나나이트의 레벨 오브 디테일 선택을 제한하는 기능입니다. 섀도 프록시가 최초로 평가되고 다른 최적화 작업이 모두 수행된 다음에도 이런 기능이 계속 필요한지는 계속해서 평가할 것입니다.

주로 나무에서 구현된 또 다른 퀄리티 향상안은 서브서피스 머티리얼 상의 섀도 텀을 평가하는 대체 방법이었습니다. 이는 포트나이트 속 나무의 나뭇잎에 사용되고 있습니다. 일반적으로 이러한 머티리얼은 나뭇잎이 빛을 마주하는 면에는 표준 '하드' 섀도 텀을 사용하고, 뒷면에는 나뭇잎을 통한 투과의 대략적 근사치로 비교적 부드러운 감쇠를 사용합니다.

기존 섀도 테크닉으로는 그림자가 매우 흐릿해서 디테일이 큰 차이를 만들지 않았습니다. 버추얼 섀도 맵을 사용하니, 이러한 나뭇잎의 노멀에서 그 지오메트릭 노멀이 셰이딩 이펙트를 부드럽게 하는 게 아니라 더 '구형'인 노멀이 되도록 조작한다는 사실과 관련된 몇 가지 새로운 오류들이 분명하게 드러났습니다. 그 결과 셰이딩 노멀의 앞뒤가 전환되면서 관련 섀도 텀의 불연속성이 발생합니다.

이 문제를 해결하고 섀도 텀에서 전체적으로 더 부드러운 룩을 확보하고자, 셰이딩 노멀에 관계없이 대략적인 투과 감쇠가 포함된 단일 텀을 사용하는 대체 서브서피스 섀도 모드를 구현했습니다. 또한 머티리얼 오파시티를 바탕으로 섀도 필터링 원뿔을 임의로 넓혀 내부 스캐터링을 수행한 듯한 인상도 전달합니다. 이 신규 모드는 r.Shadow.Virtual.SubsurfaceShadowMode 1로 활성화 가능하며, 향후 엔진 버전에서는 디폴트 설정이 될 가능성이 높습니다.
(왼쪽) 기존 서브서피스 모드 | (오른쪽) 향상된 서브서피스 모드(r.Shadow.Virtual.SubsurfaceShadowMode 1)

잔디

포트나이트의 잔디의 경우 비주얼과 퍼포먼스의 이유로 인해 나무나 덤불과는 다른 접근법을 취했습니다.

보통 다른 게임에서도 그렇듯, 잔디는 원래 포트나이트의 섀도 맵으로 렌더링되지 않았으며 대신 스크린 스페이스 '컨택트 섀도'에 완전히 의존했습니다. 일반적인 섀도 맵의 해상도는 잔디의 디테일을 캡처하기에 충분하지 않았기 때문입니다.

이 부분은 새로운 나나이트 지오메트리 기반 잔디와 버추얼 섀도 맵으로 재평가되었으나 결국 몇 가지 다른 이유로 인해 컨택트 섀도를 고수하기로 결정하였습니다.

첫 번째로, 아티스트들은 잔디로부터 그림자가 드리워지는 정도를 제어하길 원했지만 이 부분은 버추얼 섀도 맵으로 제공하는 게 불가능했습니다. 여기서의 목표는 잔디를 통과하는 동일량의 투과를 시뮬레이션하는 동시에 잔디 풀잎이 실제보다 다소 큰 것을 반영하기 때문입니다. 두 번째로, 새로운 잔디는 실제 지오메트리의 특성 덕분에 이미 멋진 비주얼 퀄리티 범프를 제공하였기 때문에 작업할 컨택트 섀도에도 더 나은 뎁스 버퍼를 제공하고 있었습니다. 마지막으로, 잔디 렌더링을 버추얼 섀도 맵으로 바꾸는 퍼포먼스 비용 자체는 관리 가능한 수준이긴 했지만 그렇다고 비용이 적지는 않았습니다.

완전 버추얼 섀도 맵을 갖추는 편이 더 나아 보이는 경우도 몇 가지 있는데, 특히 큰 꽃과 양치류가 그렇습니다. 하지만 전반적인 결과는 비슷했으며 아티스트들은 스크린 스페이스 방식으로 제공되는 더 부드러운 강도 제어를 선호했습니다. 비주얼 퀄리티를 비교한 결과, 이 퍼포먼스는 다른 부분의 비주얼 영향을 높이는 방향으로 활용하는 게 낫겠다고 결정했습니다.
(왼쪽) 버추얼 섀도 맵 그래스 섀도는 렌더링 비용이 더 비싸고 아트 스타일에 비해 너무 과합니다. | (오른쪽) 스크린 스페이스 컨택트 섀도는 비슷한 효과를 캡처하고 강도를 낮추어 더 많은 투과를 시뮬레이션할 수 있습니다.

또 신경써야 할 부분은 수면에 비치는 섀도였습니다. 비주얼 섀도 맵은 카메라의 뎁스 버퍼를 분석하고 해당 샘플링 위치를 라이트의 좌표 프레임에 투영하여 필요한 페이지를 결정합니다. 싱글 레이어 물과 이외의 기존 '포워드 렌더링' 기법은 뎁스 버퍼에 관여하지 않기 때문에, 특정 카메라 뷰의 경우 수면을 보았을 때 사용할 수 있는 고해상도 섀도 데이터가 없을 수도 있습니다.

그래서 물 렌더링 팀과 함께 버추얼 섀도 맵에 필요한 데이터를 제공할 뿐 아니라 다른 시스템에도 잘 통합되는 '뎁스 프리패스' 모드를 구현했습니다. 이 모드는 콘솔 변수 r.Water.SingleLayer.DepthPrepass 1로 활성화 가능합니다. 이 모드가 활성화된 상태에서는 수면이 페이지를 마킹하여 높은 퀄리티의 버추얼 섀도 맵을 보장합니다.

로컬 라이트

포트나이트에는 스포트라이트와 포인트 라이트를 조합한 로컬 라이트가 상당수 있습니다. 그 용도는 대형 천장 라이트부터 램프, 보물상자 같은 요소에 라이트 '이펙트'를 주는 등 다양합니다. 이런 로컬 라이트는 야간에 더 부각되어 보이지만 항상 태양/달 디렉셔널 라이트와 함께 존재하기 때문에 둘 다 섀도 예산에 적합해야 합니다. 보통 프레임 하나에는 컬링된 섀도를 갖춘 십여 개의 로컬 라이트가 존재합니다.
포트나이트는 보물상자로 시선을 끌고자 '이펙트' 라이트를 사용합니다.
퀄리티 측면에서는 버추얼 섀도 맵이 기존 솔루션에 비해 훨씬 낫다는 게 즉시 드러났습니다. 우선 훨씬 자세한 디테일을 캡처하면서도 기존의 섀도 맵에서 문제가 되던 바이어스 오류를 제거합니다.
(왼쪽) 섀도 맵에 지나치게 흐릿한 반그림자가 보이고 벽에 바이어스 오류가 있습니다. | (오른쪽) 버추얼 섀도 맵이 오류를 수정하고 변수 반그림자를 갖추고 있습니다.
둘째로 라이트의 '소스 반경'을 준수하면서 접점에서는 뚜렷해지고 멀어질수록 부드러워져서 물리적으로 더 그럴듯해 보이는 반그림자를 생성합니다. 이 파라미터는 기존에 무시되었기 때문에 포트나이트에 존재하는 수많은 라이트의 합리적인 소스 반경을 검토하고 설정해야 했습니다.
(왼쪽) 섀도 맵이 균등하게 뚜렷한 섀도를 갖추었으나 더 작은 디테일에서 섀도가 누락됩니다. | (오른쪽) 버추얼 섀도 맵이 에어리어 라이트 반그림자와 컨택트 하드닝을 갖추고 있습니다.
이러한 로컬 라이트의 높은 퍼포먼스 달성에는 프레임의 두 가지 측면이 포함됩니다. 바로 로컬 라이트로의 렌더링과 씬에 대한 재투영 및 필터링입니다. 이 두 영역 모두 포트나이트 배틀로얄 챕터 4에서 상당한 작업이 필요했습니다.

로컬 라이트 캐싱

섀도 맵 캐싱은 태양과 달리 포트나이트의 로컬 라이트와는 잘 맞습니다. 로컬 라이트는 보통 주변에 상대적으로 정적인 지오메트리와 함께 고정된 경우가 많습니다. 또한 벽을 통한 디스턴트 라이트 누수를 방지하고자 섀도잉을 평가하는 게 중요하긴 하지만, 비주얼 영향 자체는 훨씬 작기 때문에 프레임마다 업데이트할 정도로 중요하지는 않습니다. 고해상도 근거리 그림자의 밀도를 활용하는 데 쓰이는 계산 비용의 경우, 제각기 적은 수의 섀도잉된 픽셀에 관여하는 라이트 십여 개에 대하여 실행할 때 그 비용이 높아집니다.

이 경우에는 로컬 라이트가 화면상에서 충분히 작아서 단일 섀도 맵 페이지(128 x 128 텍셀)만 차지할 경우 '디스턴트 라이트'로 카테고리화할 수 있는 지원을 추가하였습니다. 이 모드는 콘솔 변수 r.Shadow.Virtual.DistantLightMode 1로 활성화 가능합니다. 디스턴트 라이트의 경우에는 사실상 '밀도 높은' 섀도 맵이기 때문에 대부분의 페이지 테이블 머시너리를 제거하였습니다. 나아가 이런 라이트(r.Shadow.Virtual.MaxDistantUpdatePerFrame)에 대한 업데이트는 업데이트 간 캐시된 페이지에 따라 조절하며, 지오메트리가 이동된 경우에도 해당됩니다.
로컬 라이트의 시각화입니다. 노란색 라이트 구체는 '디스턴트' 라이트가 되기에 충분할 정도로 작지만, 파란색 구체는 완전한 버추얼 섀도 맵을 얻습니다.
포트나이트에서는 프레임마다 디스턴트 라이트를 하나씩만 업데이트해 비주얼 문제를 최소화했습니다. 카메라에 더 가까운 라이트는 여전히 일반적인 방식으로 업데이트 및 무효화되는 페이지가 포함된 완전한 버추얼 섀도 맵을 얻습니다.

섀도 프로젝션 퍼포먼스

섀도 퍼포먼스의 또 다른 중요한 부분은 바로 라이트 루프에서 각 라이트의 섀도가 평가되고 적용될 때 발생합니다. 여기서는 작은 로컬 라이트가 꽤 오랫동안 골칫거리였습니다. 작은 로컬 라이트는 비교적 적은 픽셀에만 영향을 미치는 반면 각 조명 간 종속성을 갖춘 패스를 다수 실행했기 때문에 GPU 활용성이 감소했습니다.

하지만 새로운 문제는 아니기에 버추얼 섀도 맵에는 이 문제를 해결할 툴이 몇 가지 있습니다. 언리얼 엔진 5에는 여기에 도움이 될 선택사항 모드 '원 패스 프로젝션'이 있었지만, 이건 클러스터 셰이딩 사용에 묶여 있었습니다. 안타깝게도 포트나이트에서 클러스터 셰이딩을 활성화하면 이 모드로 얻는 대부분의 이점을 상쇄하는 수준의 퍼포먼스 저하가 발생했습니다. 언리얼 엔진 5.1에서는 이 둘을 분리하여 클러스터 셰이딩 없이도 원 패스 프로젝션을 사용할 수 있게 하였습니다.

'원 패스 프로젝션'이 활성화되어 있는 동안(r.Shadow.Virtual.OnePassProjection 1), 로컬 라이트에 대한 섀도는 단일 패스에서 미리 수행되며 그 결과는 섀도 계산을 라이팅과 인터리빙하는 대신 임시 버퍼에 저장됩니다. 추가적으로 그 외의 패스(반투명 볼륨 삽입)도 몇 가지 리팩터링하여 내부 루프가 아니라 미리 발생하도록 했습니다.

그 결과 이제 주어진 라이팅에 버추얼 섀도 맵만 필요한 경우, 그리고 라이트 함수 또는 섀도 마스크에 기여하는 여타 패스를 사용하지 않는 경우, 단일 파이프라인 드로 콜만으로 수행할 수 있게 되었으며 덕분에 소형 로컬 라이트에 대한 퍼포먼스가 크게 향상되었습니다.
기존 라이트 루프(1.56ms)에 GPU 장벽을 갖춘 라이트마다 인터리브된 패스가 여러 개 있어, GPU가 유휴 상태로 퍼포먼스를 낭비합니다.
최적화된 '원 패스 프로젝션' 라이트 루프(1.08 ms)는 모든 섀도를 우선 계산하여 각 라이트가 아무 장벽 없이 단일 파이프라인 드로가 될 수 있도록 합니다.

결론

이번 블로그에서 설명된 향상안 외에도 포트나이트를 넘어 광범위하게 적용될 수 있는 다양한 일반 엔진 향상 사항을 구현하였습니다. 앞으로도 아직 남아 있는 불편한 부분을 계속해서 해결해 나갈 예정입니다.

전반적으로, 캐싱 및 퍼포먼스에 대한 초기의 우려에도 불구하고 포트나이트 배틀로얄 챕터 4에서 버추얼 섀도 맵이 선보이는 룩과 퍼포먼스에 상당히 만족합니다. 여러분이 게임과 새로운 그래픽을 즐기시는 모습을 보니 굉장히 기쁩니다. 다른 개발자들이 이 기능을 사용하여 앞으로 어떤 언리얼 엔진 게임을 만들어 갈지 기대됩니다.
기술 정보에 대한 자세한 내용은 버추얼 섀도 맵 문서를 참고하세요.

    지금 언리얼 엔진을 다운로드하세요!

    세계에서 가장 개방적이고 진보된 창작 툴을 받아보세요.
    모든 기능과 무료 소스 코드 액세스를 제공하는 언리얼 엔진은 제작에 바로 사용할 수 있습니다.