저자: PZZZB
머리말 - Global/Local Tonemapping 소개
PBR(Physically Based Rendering)에서 과거에 가장 많이 이야기되던 것은 PBR Material이었다. 하지만 시간이 지나면서 이제 “PBR”이라는 말은 더 이상 Material에만 국한되지 않고, Material, Lighting, Camera의 결합을 가리키게 되었다. 다시 말해, 재질이 물리적으로 어떻게 표현되는가, 조명이 물리적으로 어떻게 시뮬레이션되는가, 그리고 이미지가 물리적으로 어떻게 생성되는가의 문제다.

설계 관점에서 “물리적 정확성”을 전제로 삼는 것은 제1원리에 매우 잘 부합한다. 예를 들어 현실 세계의 광원 단위와 강도를 그대로 게임 안으로 가져오면, 광원의 파라미터도 현실 세계에서 해당 광원이 가지는 강도를 직접 참고할 수 있다. 전체 시스템이 충분히 물리적이라면, 우리는 현실 세계와 거의 비슷한 결과를 얻어야 할 것이다.
하지만 이것은 어디까지나 이상적인 가정일 뿐이고, 실제 상황은 훨씬 복잡하다. PBR Camera의 관점에서만 보더라도 그렇다.
우리는 물리적인 방식으로 렌더링해 최종적으로 하나의 “원본 이미지(Scene-referred)”를 얻는다. 이 신호의 다이내믹 레인지는 현실 세계의 다이내믹 레인지와 비슷하다. 하지만 현재 디스플레이가 표현할 수 있는 다이내믹 레인지는 현실 세계와 비교하면 너무나 작다.

따라서 최종적으로 표시되는 결과에는 반드시 정보 손실이 발생한다.
Global Tonemapping(전역 톤매핑)을 적용하면 Scene-referred 이미지를 디스플레이 장치가 비교적 보기 좋게 표현할 수 있는 범위로 매핑할 수 있다. 우리가 잘 아는 “ACES curve”도 바로 이런 방식이다.

Global Tonemapping의 발전에 대해서는 반역자 님의 글 [1]을 참고하는 것을 추천한다. 매우 훌륭하게 정리되어 있다.
하지만 화면의 다이내믹 레인지가 더 커지면 Global Tonemapping은 점점 완벽하지 않게 된다. 지나치게 밝거나 지나치게 어두운 영역에서 디테일이 사라지기 시작한다. 개인적으로는 《사이버펑크 2077》을 플레이하면서 이런 디테일 손실을 꽤 느꼈다. 특히 차 안에 앉아 거리를 지날 때 그렇다.


그림에서 빨간색으로 표시한 영역을 보면 이미 디테일을 거의 알아볼 수 없다. 현실 생활이라면 분명 이렇게 보이지 않을 것이다.
2016년에 Bart Wronski가 쓴 글 [2]에서는 이 문제를 매우 자세히 설명하고 있다. 가능하면 먼저 읽어보고 아래 내용을 보는 것을 추천한다.
사진이나 영화 분야에서도 이 문제는 존재한다.

위 그림에서 왼쪽은 카메라가 그림자 영역을 언더 노출로 촬영한 결과이고, 오른쪽은 후반 작업을 통해 사람 눈으로 본 것에 더 가깝게 조정한 결과다.
다만 사진은 “정적”이기 때문에 촬영 전후로 다양한 해결 방법을 사용할 수 있다. 예를 들면 다음과 같다.
- 인공 보조광, 흔히 말하는 “Hack the light”
- Graduated Filter(ND 필터)
- Bounce cards
- Dodging & burning
- Shadow/highlight 조정(후반 작업 단계)
하지만 게임에서는 이런 촬영 전 단계의 조정 수단을 쓰기 어렵다. 게임의 출력 화면은 동적이고, 무엇이 출력되는지는 플레이어가 조종하는 캐릭터가 무엇을 보고 있는지와 현재 조명 환경에 달려 있다. 예를 들어 낮밤 변화나 날씨 변화 같은 요소가 있다. “Hack the light”를 예로 들면, 보통 특정 시각과 특정 위치에서 보조광을 넣는 방식인데, 조명 환경이 바뀌면 금방 티가 난다. 게다가 변화하는 Hack light를 잔뜩 관리하다 보면 프로젝트가 재앙이 된다.
후반 처리 쪽이 게임에서는 상대적으로 더 실현 가능성이 있다. 우리가 원하는 것은 화면 전체의 대비를 낮추되, 동시에 국소 영역의 대비는 유지할 수 있는 수단이다.
《갓 오브 워 4》의 Gaussian Blending Local Tonemapping [2]
Bart Wronski의 원문에서 언급한 《God of War》용 Local Tonemapping 구현 아이디어는 다음과 같다.
- 이미지에 Gaussian blur를 한 번 적용한다.
- Blur 결과를 국소 영역의 밝기 차이를 판단하는 기준으로 삼고, 이를 바탕으로 국소 이미지의 히스토그램 스트레칭 또는 대비 조정을 수행한다.

Global Tonemapping

Global Tonemapping + Gaussian Blending Local Tonemapping
저자는 글에서 더 많은 구현 세부 사항을 공개하지 않았다. 그 이유는 그가 이 방법을 다음과 같이 평가했기 때문이다.
it can work “ok”, but generates pretty bad halos.
[3]
Halo Artifact
여기서 Halo Artifact를 잠깐 설명할 필요가 있다. 어떤 국소 영역의 밝기를 변경한다고 할 때, 이 “국소 영역”은 어떻게 정의해야 할까? 단순히 이미지 상의 인접성만 고려하면, 국소 영역에 대한 수정이 주변의 원하지 않는 영역으로 퍼지기 쉽다. Photoshop의 “shadow/highlight” 기능을 예로 들어보면 다음과 같다.

Wide dynamic range image

Adjust Shadow/Highlight

Halo Artifact
지나치게 밝은 영역의 영향을 낮추려고 하면 그 조정이 밝기가 적당한 영역이나 어두운 영역으로도 퍼진다. 반대 방향도 마찬가지다.
정적 이미지라면 손으로 잘 조정해서 볼 만한 결과를 만들 수 있다. 하지만 게임에서는 움직이는 카메라 때문에 이 결함이 쉽게 눈에 띈다.
Halo Artifact를 해결하려면 Bilateral Filter [4]와 비슷한 사고방식을 사용하는 것이 좋은 아이디어일 수 있다.
《고스트 오브 쓰시마》의 Bilateral Grid Local Tonemapping [5]
Bilateral Filter는 가중치를 통해 이미지의 경계를 유지하면서 이미지의 다른 부분을 흐리게 만들 수 있다. 이를 통해 Halo Artifact를 줄일 수 있다.
하지만 Bilateral Filter를 Real-time 환경에서 구현하면 성능 비용이 낮지 않다. 이후 Chen et al., 2007 [6] 논문에서 더 효율적인 Bilateral Grid가 제안되었다.
Bilateral Grid의 아이디어는 차원을 하나 올려 문제를 해결하는 것이다. 서로 다른 값을 가진 pixel들을 서로 다른 slice로 분리한 뒤, 각 slice에 대해 blur를 수행한다. slice들이 공간적으로 분리되어 있으므로 서로 영향을 주지 않고, 결과적으로 경계를 유지하는 효과가 자동으로 만들어진다.

1D 입력 이미지를 예로 들면, 원본 이미지가 그림 a이고, 구성된 Grid는 원본의 edge를 공간적으로 분리할 수 있다(그림 b). 이후 grid와 slice에 blur 필터를 적용하고(그림 c), 마지막으로 고차원 grid에서 결과를 다시 가져온다(그림 d).
《Ghost of Tsushima》는 Bilateral Grid 기반 Local Tonemapping을 다음과 같은 흐름으로 구현했다.
Bilateral Grid 구성:
- 화면에 정렬된 Volume(3D Texture)을 만든다. Z축 눈금에는 균일하게 분포한 log-luminance, 즉 밝기에 log2를 취한 값이 배치된다.
- Volume의 각 slice는 화면에 정렬된 Grid다. 각 셀에는 float2 값 (w_i * V_i, w_i)가 채워진다. 여기서 w_i는 화면 Pixel Sample의 가중치이고, V_i는 Sample의 log-luminance다. Grid의 한 단위는 화면의 한 영역에 대응하며, 최종적으로 해당 영역 안의 모든 Pixel Sample 결과가 누적된다.
- Sample 가중치는 Sample의 log-luminance가 Z 좌표축에서 어디에 해당하는지에 따라 결정된다. 값은 보통 두 좌표 눈금 사이에 놓이므로, 각 Sample은 실제로 인접한 두 slice에 모두 기여한다.
- 이어서 Volume의 X/Y 방향, 즉 2D Grid 방향으로 반경이 큰 Gaussian blur를 적용하고, Z 방향에는 반경이 작은 blur를 적용한다. 보통 Z 방향 blur는 생략되기도 한다.
- 마지막으로 Volume을 trilinear sampling하고 normalize하면 bilaterally filtered log-luminance를 얻을 수 있다.
마지막으로 다음 공식을 통해 밝기 조정을 수행한다.

이 공식을 이해해보면 다음과 같다.
(B - M)은 영역 평균 밝기가 장면 평균 밝기에 비해 어느 정도인지 나타낸다. 즉, 국소 영역의 밝기를 의미한다.
(I_i - B)는 pixel 밝기가 영역 평균 밝기에 비해 어느 정도인지 나타낸다. 즉, 국소 영역 내부의 각 pixel 디테일 밝기를 의미한다.
따라서 이 공식의 의미는 다음과 같다. c를 통해 국소 영역의 밝기를 조절하고, d를 통해 영역 내부 디테일의 밝기를 조절한다.

Global Tonemapping

Global Tonemapping + Bilateral Grid Local Tonemapping
Ringing Artifact
다만 Bilateral 방식에는 Ringing Artifact라는 결점이 있다.

원문에서도 이 현상이 생기는 원인을 설명하고 있다 [7]. 내가 설명하지 않는 것은 절대 완전히 이해하지 못해서가 아니다 ฅʕ•̫͡•ʔฅ.
해결 방법은 Bilateral과 Gaussian을 섞어서 Halo와 Ringing 사이에서 균형을 잡는 것이다.

변경 전후 비교:

Bilateral Blur

40% Bilateral Blur + 60% Wide Gaussian Blur
《언리얼 엔진 5》의 Local Exposure [8]
2022년에 UE5 정식 버전이 출시되었을 때, 공식적으로 Local Tonemapping에 해당하는 시스템이 구현되어 있어서 꽤 놀랐다. UE5에서는 이를 Local Exposure라고 부른다.
UE5의 Local Exposure는 기본적으로 위에서 설명한 Bilateral Grid Local Tonemapping을 거의 그대로 따라 구현한 것이다. 여기서는 원리를 반복해서 설명하지 않겠다.
파이프라인 구현은 주로 3개의 Pass로 구성된다.

- LocalExposure: Bilateral Grid를 생성하는 Pass다. AddLocalExposurePass 구현을 보면 된다.
- LocalExposure - Blurred Luminance: 다운샘플링과 two-pass Gaussian blur를 포함한다. 앞서 언급한 Ringing Artifact 문제를 해결하기 위한 것이다.
- 마지막으로 Tonemap Pass에서 합산해 계산한다.
2022년 초 UE5 데모였던 《매트릭스 어웨이큰스》에서도 Local Exposure가 사용되었다.

Local Exposure Off

Local Exposure On
Exposure Fusion Local Tonemapping
약 3개월 전, Bart Wronski 대인은 2016년 첫 번째 글 이후 6년 만에 Local Tonemapping에 관한 두 번째 글 [3]을 업데이트했다. 주제는 Exposure Fusion Local Tonemapping이다.
Bilateral Grid Local Tonemapping은 Halo와 Ringing 사이에서 꽤 괜찮은 균형을 얻었지만, Local Tonemapping 파라미터를 비교적 극단적으로 설정하면 여전히 Halo Artifact가 발생하기 쉽다. 또한 국소 영역을 쉽게 “납작하게 밀어버리는” 경향도 있다. 그래서 실제 사용에서는 아티스트에게 너무 극단적인 파라미터를 쓰지 말라고 하는 수밖에 없는 경우가 많다.
이번 절에서 소개하는 Exposure Fusion은 이런 결함이 없고, 국소 대비도 더 잘 유지한다. 아래 그림은 Bilateral Grid와 Exposure Fusion이 국소 대비를 유지하는 정도의 차이를 보여준다.

Bilateral Grid

Exposure Fusion
보면 Bilateral Grid는 이미지 경계를 평탄화하려는 경향이 있는 반면, Exposure Fusion은 더 많은 국소 대비를 유지한다.
Exposure Fusion 알고리즘은 Mertens et al. [9]이 제안한 방법이다. 여러 장의 이미지, 보통 서로 다른 노출의 이미지를 혼합하면서도 디테일과 경계를 유지하고 Halo를 최소화하는 알고리즘이다.

알고리즘의 원리는 이미지에 대한 몇 가지 관찰에서 출발한다. 우리가 원하는 Local Tonemapping은 다음과 같다.

- 이미지의 경계, 즉 상관성이 약한 영역에서는 혼합 범위가 작아야 한다. 그래야 halo를 피할 수 있다. 그림의 빨간색 원 부분이 여기에 해당한다.
- 상관성이 강하고 평탄한 화면 영역에서는 혼합 범위가 더 커도 된다. 그래야 부드럽고 자연스러운 결과가 만들어지고, 시각적으로 혼합이 일어났다는 사실을 알아차리기 어렵다. 그림의 초록색 원 부분이 여기에 해당한다.
곰곰이 생각해보면 이것은 사실 다음 문장과 같다. “이미지의 서로 다른 주파수 성분에 대해 서로 다른 혼합 반경을 사용해야 한다.” 이것이 Exposure Fusion의 원리다.
Exposure Fusion 알고리즘의 단계는 다음과 같다.

- 서로 다른 노출 설정을 통해 혼합할 여러 장의 이미지를 얻는다. 수가 많을수록 좋지만, 보통은 3장이면 충분하다.
- 혼합할 각 이미지에 대해 대응하는 밝기 맵을 생성한다.
- 밝기 맵에 대해 Laplacian Pyramid(라플라시안 피라미드) 를 생성한다. 원하는 레벨까지 내려가도록 설정할 수 있다 [10].
- 혼합 가중치 맵을 생성한다. 가중치 맵은 원본 이미지의 여러 지표, 예를 들어 “채도, 대비, 노출도” 같은 값으로 만들 수 있다. 저자는 over-saturated나 over-contrasty를 피하기 위해 노출도만 사용하는 것을 권장한다.
- 가중치 맵에 대해 Gaussian Pyramid(가우시안 피라미드) 를 생성한다 [10].
- 피라미드를 순회하기 시작한다. 먼저 피라미드 최상위 레벨의 Gaussian 밝기 맵을 가중치 맵에 따라 혼합한다. Laplacian Pyramid의 최상위 레벨은 Gaussian 밝기 맵과 동등하다.
- 피라미드를 아래로 내려가며 각 레벨의 Laplacian 밝기 맵을 대응하는 가중치 맵에 따라 혼합한다.
- 혼합된 피라미드를 원본 이미지로 복원하면 원하는 결과를 얻을 수 있다. 렌더링 파이프라인에서는 이 단계 이후에 Exposure와 Global Tonemapping을 수행한다.
저자는 원문에서 꽤 많은 제어 파라미터를 설정했으며, 함께 제공되는 web demo도 완전히 오픈소스로 공개되어 있다!
《파 크라이 5》의 GI-Based Local Tonemapping [11]
앞에서 소개한 것은 모두 이미지 후처리 방식의 Local Tonemapping이다. 그리고 Exposure Fusion 버전의 Local Tonemapping은 국소 대비 유지와 Halo 최소화 측면에서 거의 완성형에 가깝다.
다만 여기서는 《Far Cry 5》에서 사용한, 이미지 후처리 기반이 아닌 방법을 하나 더 보충해보려 한다. 다음을 생각해보자.
Bilateral Blur가 Local Tonemapping/Local Exposure에 사용될 수 있는 이유는 다음과 같다.
- 화면 2D 공간에서는 가까이 있지만, 장면 3D 공간에서는 멀리 떨어진 영역을 구분할 수 있다. 따라서 Halo를 줄일 수 있다.
- Blur 결과가 국소 평균 밝기를 나타낼 수 있다.
사실 이 조건을 근사적으로 만족하는 기존 데이터가 하나 있다. 바로 3D 장면의 저주파 GI, 즉 Indirect sunlight + skylight(with occlusion)이다.


물론 GI가 영역 평균 밝기를 완벽하게 반영하는 것은 아니고, 대규모 장면에서 skylight occlusion의 정밀도도 제한적이다.
하지만 Local Tonemapping이 가장 필요한 장면은 보통 “실내에서 실외를 보거나, 실외에서 실내를 보는” 상황이다. 이때는 실내외 GI의 차이가 충분히 크다.
구현 단계는 다음과 같다.
- 현재 장면의 노출을 계산한다.
- 현재 pixel의 GI Average Luminance, 즉 Indirect sunlight + skylight(with occlusion)를 계산한다.
- GI Average Luminance와 장면 노출의 차이에 따라 lighting 결과를 스케일링한다. 의사코드는 다음과 같다.

결과:


원문에서는 전후 이미지 차이가 아주 크지는 않지만, 실외 디테일 손실 때문에 게임플레이가 영향을 받는 문제를 해결하기에는 충분했다고 설명한다.
기타 자료
좋은 글로는 후위안밍 선생님의 《Taichi로 GPU 이미지 처리 구현하기: 입문에서 입마까지》 [12]도 추천한다. 이 글에서는 Bilateral Grid의 구현 과정을 더 자세히 설명하고 있다.
정리
이 글에서는 왜 Local Tonemapping이 필요한지, 그리고 지금까지 실시간 렌더링에서 구현된 여러 방안을 간단히 정리했다. 더 자세한 내용은 역시 직접 참고 문헌을 읽어보는 것을 추천한다. 틀렸거나 빠진 부분이 있다면 보충해주길 바란다.
끝.
PS: Zhihu 글 편집기는 왜 개편할수록 더 쓰기 어려워지는지 v≡(▔﹏▔)≡. Markdown 가져오기도 한참을 해도 안 되고, 이미지와 인용도 전부 손으로 복사해야 한다.
PPS: 취했다. 왜 한 줄에 이미지를 두 장 못 넣는 거냐. 이미지 양도 많고 사이즈도 크지만 그냥 감안해서 봐주길. Zhihu, 죽어라!!
참고
- Tone mapping 진화론
- Localized tonemapping – is global exposure and global tonemapping operator enough for video games?
- https://bartwronski.com/2016/08/29/localized-tonemapping/
- Exposure Fusion – local tonemapping for real-time rendering
- https://bartwronski.com/2022/02/28/exposure-fusion-local-tonemapping-for-real-time-rendering/
- Bilateral Filter
- https://en.wikipedia.org/wiki/Bilateral_filter
- Real-Time Samurai Cinema Lighting, Atmosphere, and Tonemapping in Ghost of Tsushima
- https://advances.realtimerendering.com/s2021/jpatry_advances2021/index.html#/125
- Real-time Edge-Aware Image Processing with the Bilateral Grid
- https://people.csail.mit.edu/sparis/publi/2007/siggraph/Chen_07_Bilateral_Grid.pdf
- Ringing Artifact
- https://advances.realtimerendering.com/s2021/jpatry_advances2021/index.html#/138
- Unreal Engine 5.0 release notes - Local Exposure
- https://docs.unrealengine.com/5.0/en-US/unreal-engine-5-0-release-notes/#localexposurepost-processing
- Exposure Fusion
- https://mericam.github.io/exposure_fusion/index.html
- Laplacian Pyramid and Gaussian Pyramid
- https://paperswithcode.com/method/laplacian-pyramid
- The Challenges of Rendering an Open World in Far Cry 5
- http://advances.realtimerendering.com/s2018/The Challenges of Rendering an Open World in Far Cry 5 (With Notes).pdf
- Taichi로 GPU 이미지 처리 구현하기: 입문에서 입마까지
원문
(71 封私信 / 30 条消息) Tonemapping不够用了: Local Tonemapping方案总结 - 知乎
'TECH.ART.FLOW.IO' 카테고리의 다른 글
| [번역] 넷이즈 레이훠 LGDC 시리즈 《영겁무간 모바일》RenderGraph 개조 공유 (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 |