[Unreal Engine 5] Virtual Shadow Map

2025. 7. 29. 19:27·언리얼 엔진

기본 아이디어

Shadow Map 해상도가 낮으면 그림자에 aliasing이 발생한다.

이를 해결하기 위해 다양한 시도들이 있다.

  • Cascaded Shadow Map : 거리에 따른 Shadow map 분리
  • Variance Shadow Map : 텍스쳐 샘플링 때, 분산에 따른 필터링 방법

…

Virtual Shadow Map은 Shadow map 해상도를 16K 같이 고해상도로 늘리는 방식이다.

출처 : https://zhuanlan.zhihu.com/p/489550318

 

이 방식은 aliasing은 줄이겠지만, 16K 텍스쳐는 메모리를 엄청 사용한다. 단순히 D32 float의 depth만 저장하더라도 2^14 * 2^14 * 4 = 10억 Byte = 1GB

16K 텍스쳐 한장에 1GB 정도 사용한다. Mipmap까지 포함하면 대략 1.3GB 정도는 사용한다.

Directional Light의 경우에는 CSM과 비슷한 방식으로 거리에 따라 16개 level로 나누어 각 level이 16K텍스쳐를 가지고, Point Light는 큐브맵이니 6개의 16K 텍스쳐를 사용한다.

Directional Light : 20.8 GB

Point Light : 7.8 GB

이는 VideoMemory에서 사용하기에 말도 안되는 수치이고, 여기서 Virtual Shadow Map에서 “Virtual”의 개념이 사용된다.

 

Virtual Memory

컴퓨터 사이언스 전공자들이면 대부분 알겠지만, Virtual Memory는 OS에서 사용되는 개념인데 Memory에 (매우 큰) 가상 공간을 할당하는 개념이다. 가상으로 큰 메모리를 할당해놓고, 실제로 사용하는 부분만 물리 메모리 (Physical Memory)에 올려놓고 사용한다.

대신 OS단에서 가상메모리 접근을 했을 때, 물리 메모리에 데이터가 없다면 빠르게 디스크에서 가져와 올려놓는 작업을 몰래 하고있다.

그래서 그 윗단에서는 이에 대해서 고려하지 않고 가상메모리 주소만 접근해도 데이터를 얻을 수 있고, 마치 엄청 큰 메모리를 사용하는 것처럼 구현할 수 있다.

실제로 물리 메모리에 없어서 가져오는 동작을 page fault라고 하며, 이는 엄청난 성능 하락을 발생시키지만 자세한 내용은 다루지 않기로 한다.

다시 Virtual Shadow Map 으로

Virtual Shadow Map도 같은 원리이다. 대신 하드웨어 레벨이 조금 다른데, OS는 CPU Memory를 가상으로 사용하는 것이라면 VSM은 GPU Memory를 가상으로 사용하는 것이다.

또한 필요할 때 page fault를 발생시키는 것은 아니고, Shadow map은 현재 View 렌더타겟 기준으로 내가 요청할 shadow map의 부분을 미리 알 수 있기 때문에, 미리 체크하는 방식으로 동작한다.

 

 

동작 분석

출처 : https://zhuanlan.zhihu.com/p/489550318

 

위 그림은 가상의 16k * 16k의 Shadow map 이다.

먼저 Shadow map 을 Page 단위로 쪼갠다. (이를 Virtual Page, 가상 페이지라고 부름)

Page 는 128128의 크기를 가지며 16K의 텍스쳐는 128128의 page를 가지게 된다.

출처 : https://zhuanlan.zhihu.com/p/489550318

Depth Pass를 지나고나면 현재 프레임의 깊이를 알 수 있는데, uv와 depth를 world 좌표로 변환, 이를 Shadow space로 변환하면 대응되는 Shadow map page를 알 수 있다.

우리는 해당 page를 사용할 것이므로 “사용 중” 이라고 표시한다.

 

출처 : https://zhuanlan.zhihu.com/p/489550318

 

모든 페이지를 표시해주었으면, 우리는 녹색표시 이외의 타일에 대해서는 shadow map을 그려줄 필요가 없다.

그러므로 사용 중인 Page만 모아서 실제 PhyicalPage 공간을 할당한다. 그림에는 Physical Image라고 적혀있지만, 실제 UE5 리소스 네이밍은 PhysiclaPagePool이다.

 

출처 : https://zhuanlan.zhihu.com/p/489550318

 

실제로는 이렇게 생겼다.

 

r.Shadow.Virtual.MaxPhysicalPages으로 최대값이 결정되고, 예시로 r.Shadow.Virtual.MaxPhysicalPages = 1024인 환경에서는

128*8 의 페이지가 할당되고 페이지의 크기는 128이므로 PhysiclaPagePool의 크기는 16384x1024으로 할당된다.

 

Page Pool Overflow

맵이 아주 넓고, depth 분포가 다양한 Scene의 경우, 위에서 설정한 1024보다 많은 페이지 개수를 사용할 수 있다.

이 경우에는 "Virtual Shadow Map Page Pool overflow (%d page allocations were not served), this will produce visual artifacts (missing shadow), increase the page pool limit or reduce resolution bias to avoid.\\n”

라는 오류가 발생하며, 초과된 페이지의 경우에는 그림자가 그려지지않는다.

 

Shadow Depth Pass 동작

Shadow depth pass 에서는 먼저 가상 이미지에서 어떤 Virtual Page에 있는지 확인을 한다. 그리고 이를 Phyical Page Pool 에서의 Physical Page 위치로 변환한 다음에 그곳에 depth값을 써주면 된다.

그리고 Lighting Pass 에서 이를 읽을 때 역시 같은 방식으로 가상 Page → 물리 Page 변환해서 depth값을 읽어 사용하면 된다.

Clipmap

장면이 아주 큰 경우에는 16K일지라도 한 장의 Shadow map으로는 부족하다. 따라서 Directional Light는 카메라에서부터의 거리에 따라 늘어나는 clipmap 구조를 사용한다. 각 clipmap level은 고유의 16K VSM을 가진다. 각 clipmap level은 같은 해상도를 가지지만 이전 level보다 2배의 반지름 범위를 커버한다.

 

출처 : https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine

 

기본값으로 clipmap level은 6 ~ 22 까지로 사용되며 이것은 2^6 cm ~ 2^22 cm (40km) 까지 shadow map이 사용됨을 의미한다.

그리고 2^6 ~ 2^7 cm 사이를 담당하는 16K VSM 하나, 2^7cm ~ 2^8 cm 까지 담당하는 16K VSM하나 … 이렇게 16개 VSM이 사용된다.

r.Shadow.Virtual.Clipmap.FirstLevel, r.Shadow.Virtual.Clipmap.LastLevel 로 이 값은 조절가능하다.

사실 이름이 왜 Clipmap인지는 잘 모르겠다. Mipmap이라고 하기엔 크기가 줄지는 않고,, virtual page개념으로 멀리 있는 VSM의 사용빈도가 알아서 줄어드니까 Clipmap이라고 표현한게 아닐까 싶다.

Local Light

Spot Light : 하나의 16k VSM을 사용하는데, clipmap 대신 mip chain을 사용하여 shadow level of detail을 조절한다.

Point Light : 각 면은 각각16k VSM을 가져 총 6장을 사용한다. 역시 mip chain을 사용한다.

 

해상도 조절

r.Shadow.Virtual.ResolutionLodBiasDirectional 로 directional light의 해상도를 늘릴 수 있다. 값 -1당 2배씩 늘어난다.

r.Shadow.Virtual.ResolutionLodBiasLocal : 로컬 라이트의 해상도 조절.

 

렌더 패스 분석

렌더 패스 분석은 다음 에서 마저 분석해보자.

 

Reference

https://zhuanlan.zhihu.com/p/489550318

https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine

'언리얼 엔진' 카테고리의 다른 글

[Unreal Engine 5] Virtual Shadow Map - 렌더패스 분석  (2) 2025.08.21
[Unreal Engine 5] Nanite Basepass 분석  (5) 2025.07.25
Expert's guide to unreal engine performance  (0) 2023.09.01
UE5.1 Planar reflection과 VSM 동시 사용 시 프레임 드랍 문제  (0) 2023.08.03
[언리얼 엔진] Referencing Assets 쿠킹 테스트  (0) 2023.03.24
'언리얼 엔진' 카테고리의 다른 글
  • [Unreal Engine 5] Virtual Shadow Map - 렌더패스 분석
  • [Unreal Engine 5] Nanite Basepass 분석
  • Expert's guide to unreal engine performance
  • UE5.1 Planar reflection과 VSM 동시 사용 시 프레임 드랍 문제
jooh3444
jooh3444
게임엔진 / 그래픽스 개발 블로그
  • jooh3444
    Jooh 개발 블로그
    jooh3444
  • 전체
    오늘
    어제
    • Dev blog (18)
      • OpenGL (7)
        • CS-248 셰이더 프로그래밍 (7)
      • 언리얼 엔진 (7)
      • 기타 (1)
      • Computer Graphics (3)
  • 블로그 메뉴

    • 홈
    • About
    • github
  • 인기 글

  • 태그

    multi-scattering brdf
    Computer Graphics
    그래픽스
    Enviroment Lighting
    UE5
    범프 매핑
    twopass occlusion culling
    Unreal Engine 5
    Shadow map
    Shader
    Nanite
    Virtual Shadow Map
    Unreal Engine
    UE5 bugfix
    셰이더
    bDontLoadBlueprintOutsideEditor
    Blueprint load by path
    Shader Programming
    OpenGL
    셰이더 프로그래밍
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
jooh3444
[Unreal Engine 5] Virtual Shadow Map
상단으로

티스토리툴바