역자의 말: 레이화 사업부는 제가 근무 하던 반고 사업부와 형제 사업부입니다. 이후 두 사업부는 레이화 사업부 하나로 병합되었었죠. 약 3000 명 규모의 넷이즈 1급 사업부이며 항저우 제1캔퍼스에 자리 하고 있습니다. 오픈월드 서브컬처 게임 ' 무한대' 와 '나라카' 와 '역수한' 및 '천녀유혼' 시리즈 개발로 유명합니다.
저자: 넷이즈 게임즈 레이화 사업부
전역 조명(Global Illumination) (GI)은 게임에서 널리 사용하는 조명 기법입니다. 빛의 전파 원리를 바탕으로 다양한 방식으로 사실적인 조명 효과를 구현합니다. 이 글에서는 사전 베이크를 기반으로 한 실시간 GI 기법을 구현했습니다. 이 기법은 동적 조명과 동적 오브젝트를 모두 지원합니다.
1. GI 기술 개요
1.1 GI의 원리
현실에서 빛은 공기를 통과해 물체 표면에 도달합니다. 빛의 일부는 표면에 흡수되고, 나머지는 반사되어 다시 공간을 지나 다른 물체를 비춥니다. 빛의 에너지가 소진될 때까지 전파와 반사가 반복됩니다. 반사된 빛이 다른 물체를 다시 비추는 현상을 간접 조명이라고 하며, 전역 조명(Global Illumination, GI)이라고도 합니다.
장면에서 GI를 켜고 끈 결과 비교

장면에서 GI를 켜고 끈 결과 비교
실시간 렌더링에는 VXGI, DDGI, SDFGI 등 다양한 실시간 GI 기법이 있습니다. 이 기법들의 공통된 목표는 물체 표면에서 반사된 빛이 주변 표면을 비추도록 하는 것입니다. 아래 그림과 같습니다.
직접 조명과 간접 조명 비교

직접 조명과 간접 조명 비교
1.2 PRTGI
이 글에서 사용하는 GI 기법은 사전 계산 복사 전달 기반 전역 조명(Precomputed Radiance Transfer Global Illumination, PRTGI)을 기반으로 합니다. 주변 장면의 조명 정보를 구면 조화 계수 형태로 Probe에 저장합니다. 실행 중인 오브젝트는 가장 가까운 Probe에서 주변 조명 정보를 읽어 GI를 구현합니다. 장면 조명 정보를 Probe에 저장하므로 기존 라이트맵 방식보다 동적 오브젝트에 GI를 적용하기 쉽습니다. 따라서 UE4와 Unity 같은 상용 엔진은 라이트맵을 보완하는 용도로 이 기법을 사용해 장면 내 동적 오브젝트에 GI를 제공합니다.
Unity의 Probe

Unity의 Probe
UE4의 Probe

UE4의 Probe
하지만 이러한 기법에도 한계가 있습니다. 예를 들어 Unity의 PRTGI는 오브젝트별로 보간하므로 동적 오브젝트가 너무 크면 샘플링 결과의 정확도가 떨어집니다. 또한 두 엔진 모두 장면의 조명 정보를 직접 베이크하기 때문에 조명이 바뀌어도 GI에 실시간으로 반영되지 않아 동적 조명을 지원하지 못합니다.
2. 실시간 PRTGI 기술
유비소프트는 GDC16에서 《Global Illumination in Tom Clancy's The Division》을 발표하며 실시간 PRTGI를 소개했습니다. 이 기법은 기존 PRTGI의 대형 오브젝트 지원 부족과 동적 조명 미지원 문제를 해결했습니다. 이 글에서는 발표 내용을 참고해 실시간 PRTGI를 프로젝트에 구현하고 적용했으며, Probe 배치 알고리즘, 정보 베이킹, Volume Lightmap 등의 측면을 개선했습니다.
다음은 프로젝트에서 PRTGI 적용 여부에 따른 결과 비교입니다.
PRTGI를 적용하지 않은 장면

PRTGI를 적용하지 않은 장면
PRTGI를 적용한 장면

PRTGI를 적용한 장면
PRTGI를 적용하지 않은 장면

PRTGI를 적용하지 않은 장면
PRTGI를 적용한 장면

PRTGI를 적용한 장면
2.1 GI 데이터 구조
GI 데이터 구성 요소

GI 데이터 구성 요소
GI의 동적 조명 처리(이하 Relight)는 크게 세 가지 데이터 구조로 구성됩니다. 작은 순서부터 Surfel, Brick, Probe입니다.
Surfel은 실시간 PRTGI의 가장 기본 단위입니다. 각 Surfel은 자신의 Position과 해당 위치의 Normal 및 Albedo 정보를 저장하며, 배치 밀도는 1m당 하나입니다.
Brick은 Surfel의 상위 단위로, 4m당 하나씩 배치됩니다. 자신의 영역 안에 있는 Surfel의 인덱스를 저장하며 위치 정보는 별도로 저장하지 않습니다.
Probe는 Brick의 상위 단위이며 배치 방식에 따라 밀도가 달라집니다. 자신의 위치, 주변에서 색상에 기여하는 Brick의 인덱스와 가중치, 하늘 가시성(Sky Visibility) 정보를 저장합니다.
1m당 하나씩 배치된 Surfel

1m당 하나씩 배치된 Surfel
4m당 하나씩 배치된 Brick

4m당 하나씩 배치된 Brick
Probe와 색상에 기여하는 Brick

Probe와 색상에 기여하는 Brick
실행 중 Surfel은 현재 조명 정보와 저장된 Normal, Albedo, Position을 바탕으로 Relight를 수행합니다. Brick은 자신의 영역에 속한 모든 Surfel 결과를 평균 내고, Probe는 인덱스와 가중치를 이용해 Brick의 평균 색상을 합산합니다. 이 과정을 통해 PRTGI가 동적 조명을 지원합니다.
2.2 Probe 베이크
Probe와 Probe에 저장되는 Surfel 정보

Probe와 Probe에 저장되는 Surfel 정보
Probe가 장면 정보를 얻는 방법은 간단합니다. Probe가 위치한 지점에서 Cubemap을 베이크한 뒤, 필요한 정보를 샘플링해 원하는 형식으로 변환하고 저장합니다.
장면 정보를 베이크할 때는 머티리얼이 각각 Albedo, Normal, WorldPos만 출력하도록 설정합니다. 그런 다음 Probe 위치에서 128×128 해상도의 Cubemap 3장을 베이크해 각 정보를 저장합니다. 이어 Probe에서 구형 방향으로 64개의 광선을 무작위 발사하고, 세 Cubemap에서 샘플링한 정보를 Surfel로 저장합니다. Surfel을 얻은 뒤에는 일정 범위(4m) 안의 Surfel 인덱스를 하나의 Brick으로 묶고, 해당 Brick 인덱스를 Probe에 저장합니다.
장면 정보 베이킹 절차

장면 정보 베이킹 절차
서로 다른 Probe가 같은 위치의 Surfel을 샘플링할 수 있습니다. 데이터 양을 줄이려면 같은 위치의 Surfel을 평균 내어 병합해야 합니다. Surfel의 해상도는 1m이며, 많은 오브젝트는 1m³보다 훨씬 작습니다. 따라서 하나의 Surfel 영역 안에 매우 다른 방향의 Normal이 함께 들어갈 수 있습니다(예: 얇은 벽). 특정 Probe를 등지는 Surfel은 해당 Probe의 조명에 기여하지 않으므로, Surfel과 Brick의 해상도 단위에서 Normal 차이가 큰 요소들을 서로 분리해야 합니다.
같은 위치에서 방향이 다른 데이터

같은 위치에서 방향이 다른 데이터
여기서는 Surfel과 Brick을 해상도 범위 내에서 6개의 주 방향(±x, ±y, ±z)으로 나눕니다. 같은 위치에서 Normal이 다른 Surfel은 자신의 Normal에 따라 주 방향 하나를 선택해 저장합니다. 같은 위치에 있고 Normal은 다르지만 주 방향이 같은 Surfel들은 해당 방향 단위로 평균 Normal과 평균 Albedo를 구한 뒤 해당 주 방향에 저장합니다. Brick도 같은 방식으로 처리하며 Normal의 평균도 계산합니다. 마지막으로 Probe가 Brick 인덱스를 저장할 때 Brick의 현재 Normal이 가중치에 미치는 영향을 반영합니다. Probe 정보 저장이 끝나면 Brick의 Normal 정보는 더 이상 필요하지 않으므로 보존하지 않아도 됩니다.
앞서 설명했듯이 Probe는 현재 위치에서 하늘이 얼마나 보이는지를 나타내는 Sky Visibility 정보를 저장합니다. Probe에서 여러 방향으로 광선을 발사해 오브젝트에 부딪히면 해당 방향은 하늘이 보이지 않는 것으로, 아무것에도 부딪히지 않으면 하늘이 보이는 것으로 판정합니다. 모든 방향의 가시성을 가중 합산해 최종 Sky Visibility를 구합니다. 실제 구현에서는 Probe가 구형 광선을 발사해 Surfel을 샘플링할 때 Cubemap의 A 채널을 읽습니다. A 값이 0이면 해당 방향에서 하늘이 보이는 것으로 처리합니다.
Probe가 출력한 Sky Visibility

Probe가 출력한 Sky Visibility
PRTGI는 Surfel의 Relight를 마친 뒤 Probe를 계산하는 단계에서 Sky Visibility를 바탕으로 하늘색을 더합니다.
Sky Visibility만 출력한 장면

Sky Visibility만 출력한 장면
Sky Visibility는 먼 거리의 AO 문제를 완화할 수 있습니다. 유비소프트의 《더 디비전 2》에서는 SSAO + Sky Visibility를 기본으로 하고, 특수한 경우 데칼 AO를 추가해 AO를 처리합니다.
2.3 GI의 동적 조명
베이크한 Surfel, Brick, Probe 데이터를 청크 단위로 저장하면 실행 중 카메라 위치에 맞는 청크를 불러와 데이터를 Compute Shader에 전달해 계산할 수 있습니다.
Surfel에는 WorldPos, Normal, Albedo가 저장되어 있으므로 조명 계산은 Surfel 단위로 수행됩니다. 먼저 각 Surfel은 WorldPos를 기준으로 자신에게 영향을 주지 않는 광원을 제외합니다. 이어 Normal과 Albedo로 조명 결과를 계산하고, WorldPos로 샘플링한 ShadowMap 결과를 더해 그림자 정보를 얻습니다.
ShadowMap의 특성상 뷰 프러스텀 안에 그림자를 드리우지 않는 오브젝트는 ShadowMap을 그릴 때 제외됩니다. 청크 단위로 로드한 Surfel 중 상당수는 뷰 프러스텀 밖에 있어 샘플링한 그림자 정보가 부정확하고, 카메라가 움직일 때 값이 튈 수 있습니다. 이를 방지하려면 각 Surfel에 그림자 정보를 저장하는 Cache가 필요합니다. 신뢰할 수 있는 그림자 정보를 얻으면 Cache에 저장하고, 다음으로 신뢰 가능한 정보를 얻을 때까지 해당 값을 계속 사용합니다.
Surfel의 조명을 다시 계산한 뒤 Brick은 저장된 Surfel 인덱스를 사용해 담당 영역의 결과를 가져오고 평균을 구합니다.
Brick의 평균을 구한 뒤 Probe는 저장된 Brick 인덱스와 가중치에 따라 해당 Brick들을 혼합합니다. 그리고 저장된 Sky Visibility 정보를 바탕으로 하늘빛을 Probe 결과에 합성합니다.
유비소프트는 실시간 하늘의 특성에 맞춰 하늘빛 계산 결과를 하나의 텍스처로 단순화해 GI 시스템이 읽도록 했습니다. 이 프로젝트에서는 날씨별로 높은 고도에 Probe를 배치해 현재 하늘빛을 베이크합니다. 하늘빛을 보간할 때 해당 고도 Probe의 색상 정보를 읽습니다.
2.4 볼륨 라이트맵
Probe 색상 정보를 적용하는 방식으로 구면 조화가 아닌 《하프라이프 2》에서 사용된 Ambient Cube 알고리즘을 사용합니다. 알고리즘과 샘플링 결과는 다음과 같습니다.
Ambient Cube 알고리즘

Ambient Cube 알고리즘
Ambient Cube 샘플링(오른쪽 아래)과 다른 샘플링 방식의 비교

Ambient Cube 샘플링(오른쪽 아래)과 다른 샘플링 방식의 비교
대형 오브젝트의 GI 지원 문제를 해결하기 위해 UE4와 유비소프트는 Volume Lightmap 개념을 도입했습니다. Probe에서 얻은 조명 결과를 3D Texture에 저장하고, 각 픽셀은 자신의 위치와 Normal을 기준으로 3D Texture를 읽습니다. 계산식에서 알 수 있듯이 6개 주 방향의 색상 정보(cAmbientCube)가 필요하므로 Volume Lightmap은 3D Texture 6장으로 구성됩니다.
장면의 Volume Lightmap

장면의 Volume Lightmap
유비소프트는 32×16×32 픽셀 크기의 3D Texture를 사용했습니다. 픽셀 하나가 4m를 담당하므로 플레이어 주변 128×64×128m 범위를 커버합니다. 이 범위를 벗어나는 픽셀은 저장된 하늘빛을 직접 읽습니다.
더 넓은 GI 범위를 지원하기 위해 카메라 위치를 3D Texture의 중심이 아닌 가장자리에 둡니다. 이렇게 하면 제한된 픽셀 수로 더 먼 거리까지 커버할 수 있습니다.
Probe가 Brick과 하늘빛을 가중 혼합한 뒤, 3D Texture는 각 위치에서 가장 가까운 Probe의 결과를 해당 픽셀에 기록합니다.
Surfel은 Relight 과정에서 직접 조명 결과뿐 아니라 자신의 위치와 Normal로 이전 프레임의 Volume Lightmap 결과도 샘플링합니다. 이를 현재 프레임 결과와 혼합해 여러 번 반사된 빛의 효과를 만듭니다.
2.5 청크 단위 로딩
대규모 월드를 지원하려면 PRT 데이터를 청크로 나누고 플레이어 주변의 PRT 정보만 동적으로 로드해야 합니다. PRT 청크를 배치할 때는 카메라를 생성해 현재 청크의 깊이 정보를 위에서 아래로 촬영합니다. 깊이 정보를 얻지 못한 위치에는 청크를 배치하지 않습니다.
장면의 청크

장면의 청크
2.6 자동 Probe 배치
현재 청크 위쪽에 카메라를 배치해 높이 맵을 생성합니다. 높이 맵의 해상도는 픽셀 하나당 4m이며, 4m 간격으로 해당 높이에 Probe를 배치합니다. 인접 픽셀 간 깊이 차가 4m를 넘으면 더 낮은 Probe 위에 새 Probe를 추가합니다. 새 Probe의 높이는 낮은 Probe와 높은 Probe의 중간값으로 정합니다.
산 표면을 따라 배치한 Probe 결과

산 표면을 따라 배치한 Probe 결과
2.7 Volume Index
3D Texture는 공간상에서 연속적이고 규칙적인 반면 Probe는 불연속적인 위치에 배치됩니다. 각 Volume Lightmap 픽셀이 가장 가까운 Probe를 빠르게 찾도록 3D Texture의 밀도(4m당 하나)에 맞춰 규칙적인 기준점을 공간에 배치합니다. 각 기준점에는 가장 가까운 Probe의 인덱스를 저장합니다. 실행 중에는 3D Texture가 각 픽셀의 기준점 위치를 통해 해당 Probe를 찾습니다.
인덱스 시각화 결과(파란색)

인덱스 시각화 결과(파란색)
Probe는 청크 단위로 로드되므로 각 인덱스는 자신이 속한 청크의 Probe만 참조할 수 있습니다. 인덱스가 청크 경계에 가까우면 월드 전체에서 가장 가까운 Probe가 아니라 해당 청크 안에서 가장 가까운 Probe를 가져와 경계에서 정확도가 떨어질 수 있습니다. 이를 해결하기 위해 각 청크의 인덱스 영역을 바깥쪽으로 한 겹 확장합니다. 베이크 시 청크 간에 겹치는 인덱스를 비교해 Probe와의 거리가 가장 가까운 결과만 남기고 나머지 중복 데이터는 버립니다.
차폐 정보가 있는 인덱스에서 서로 반대 방향의 Probe 두 개를 저장한 예시

차폐 정보가 있는 인덱스에서 서로 반대 방향의 Probe 두 개를 저장한 예시
인덱스와 Probe 사이에 차폐물이 있을 때 차폐물이 있는 방향의 Probe를 샘플링하면 빛샘이 발생할 수 있습니다. 이를 막으려면 차폐 방향과 반대쪽에서 가장 가까운 Probe를 선택해야 합니다. 따라서 베이크할 때 기준점에서 서로 반대 방향에 있는 최근접 Probe 두 개를 저장합니다. 가장 가까운 Probe와 기준점 사이가 차폐된 경우, 해당 픽셀은 방향에 따라 두 Probe를 각각 샘플링합니다.
2.8 기법의 한계
실시간 PRTGI는 대형 동적 오브젝트와 동적 조명을 지원하지만, 다음과 같은 한계가 있습니다.
- 베이크가 끝난 뒤에는 동적 오브젝트가 GI를 받기만 하고 GI를 생성하지는 못합니다. 즉 주변 환경에 영향을 줄 수 없습니다.
- GI 범위가 128×64×128m이고 Probe가 4m 간격으로 배치되어 정밀도가 아주 높지는 않습니다. Clipmap를 이용해 먼 곳의 정밀도를 낮추고 가까운 곳의 정밀도를 높일 수 있습니다.
- 현재 Emission은 지원하지 않습니다. 자체 발광 GI는 SSGI 결과를 혼합해 구현합니다.
정적 오브젝트는 GI를 받고 주변 오브젝트에도 영향을 줄 수 있습니다.

정적 오브젝트는 GI를 받고 주변 오브젝트에도 영향을 줄 수 있습니다.
동적 오브젝트는 GI를 받을 수 있지만 주변 오브젝트에 영향을 주지는 못합니다.

동적 오브젝트는 GI를 받을 수 있지만 주변 오브젝트에 영향을 주지는 못합니다.
2.9 요약 및 향후 기술 전망
실시간 PRTGI는 동적 광원과 대형 동적 오브젝트 지원 문제를 해결했습니다. 이 GI는 이펙트와 볼류메트릭 포그에도 적용할 수 있습니다. 다만 라이트맵이나 동적 조명을 지원하지 않는 PRT에 비해 저장해야 할 데이터가 크게 늘어납니다.
다음은 동적 GI를 켰을 때와 껐을 때의 결과 비교입니다.


다음은 프로젝트의 GI 데모입니다.

동적 조명 데모

동적 조명 및 동적 오브젝트 데모
더 높은 GI 정밀도가 필요한 장면에서는 4m당 Probe 하나로는 부족합니다. Probe 배치 알고리즘을 개선하고 옥트리 구조로 장면의 3차원 정보를 구성한 뒤 옥트리의 각 노드에 Probe를 배치하면 Probe 밀도를 높일 수 있습니다. 또한 위에서 아래로 Probe를 배치할 때 처마 같은 오브젝트에 가려지는 문제도 줄일 수 있습니다. Volume Lightmap은 규칙적인 3D Texture 대신 Clipmap을 사용하도록 개선할 수 있습니다. 이 방식은 먼 거리의 GI 정밀도는 낮추지만 가까운 곳의 정밀도를 높여 줍니다.
참고 문헌:
1.[GDC16]Nikolay Stefanov, Global Illumination in Tom Clancy’s The Division
2.[GDC12]Mickael Gilabert, Deferred Radiance Transfer Volumes: Global Illumination in Far Cry 3
'TECH.ART.FLOW.IO' 카테고리의 다른 글
| CaptureCanva (0) | 2026.10.09 |
|---|---|
| [번역] 프로젝트의 인게임 조명 환경 Lookdev 설정 방법 (0) | 2026.09.29 |
| [번역] UE5 렌더링. GPUScene과 InstanceCulling (0) | 2026.09.28 |
| [번역] UE5 GC의 변경 사항 (1) | 2026.09.27 |
| [번역] UE4/5 오클루전 컬링(Occlusion Culling) 간단 분석 (0) | 2026.09.17 |