Graphics Techniques

[Tone Mapping] Gamma correction과 CRT

doyyy_0 2025. 4. 9. 17:07

HDR이미지는 밝기를 0.0~1.0으로만 표현하면 다양한 빛의 밝기를 표현하지 못합니다. 따라서 16float형식이나 32float형식을 사용합니다. 16float의 범위는 약 0.0~65504.0입니다. 보통 skybox같은 이미지에 태양이 있기 때문에 skybox를 16float으로 설정합니다.

 

LDR이미지는 모니터에 표현되는 값을 위해 0.0~1.0의 값으로 정규화 되어있습니다. 그렇다면 HDR이미지를 잘 계산한 후 LDR이미지로 변환해주는 것이 필요하겠죠? 이 과정을 톤 매핑이라고 합니다.

 

Unity에서는 톤매핑의 정의를 다음과 같이 표현하기도 합니다.

"톤 매핑(Tonemapping) 은 일반적으로 컬러 값을 HDR에서 LDR (low dynamic range)로 매핑하는 과정입니다. 이는 대부분의 플랫폼에서 임의의 16 비트 부동 소수점 컬러 값을 [0,1] 범위의 기존 8 비트 값으로 매핑하는 과정을 의미합니다"

 

여기서 톤 매핑시 주의해야할 점이 있습니다. HDR을 계산하려면 렌더타겟을 DXGI_FORMAT_R16G16B16A16_FLOAT으로 설정해야합니다. DXGI_FORMAT_R16G16B16A16_FLOAT는 선형인 공간이며, LDR로 변환 시 gamma correction을 적용할 때가 있습니다.

 

예를들어 백버퍼의 포맷이  DXGI_FORMAT_R8G8B8A8_UNORM라고 합시다(보통 최종 백버퍼를 Unorm으로 사용합니다). 예전에는 CRT모니터라고 있었는데, 사람은 어두운 값을 더 차이있게 보기 때문에 CRT감마를 적용했습니다. 현재도 상황에 맞게 CRT 감마를 적용하죠. 

 

CRT감마를 이해하기 위해 다음 그림을 살펴봅시다. 

 

https://learnopengl.com/Advanced-Lighting/Gamma-Correction

 

Physical brightness는 물리적 밝기를 0.1으로 했을때 빛이 확 커지는 것을 볼 수 있습니다. 광자의 세기를 [0.0~1.0]으로 생각 해봤을 때,  0.1에서 0.2로 변하는 것을 본다면, 실제로는 광자의 수가 두배가 된 것이지만, 광자가 엄청 많아진 것으로 보입니다. 이것은 사람이 어두운 영역을 더 세밀하게 보는 특성 때문입니다.

 

따라서 Physical brightness를 CRT 감마를 적용하여, Perceived brightness로 바꿉니다. Perceived brightness는 0.1에서 0.2로 변할 때 정확히 두배로 변한것으로 보이기 때문입니다. 

 

더 자세히 이해하기 위하여 다음의 그래프를 살펴봅시다.

 

가운데 회색의 점선은 선형공간(Physical brightness 상태)입니다. 하지만 CRT감마를 적용하면 비선형 공간으로 변하고 결국 우리 눈에 적합하게 보이게 되죠.  하지만 문제는 사람들이 그리거나 할 떄 CRT감마를 적용 안 한 선형 공간에서 작업을 합니다. 그렇다면, 선형 공간에 비선형 값을 넣게 되는것이죠. 예를들어 0.5정도의 검은색을 넣고싶은데, 0.218정도를 넣어야 우리 눈에는 0.5정도로 보인다는 것입니다. 하지만 어쩔 수 없습니다. pbr등 쉐이더에서 계산할 때는 선형공간에서 이루어져야만하기 때문에 선형공간에 그냥 비선형 값을 넣는 것입니다.(계산은 무조건 선형공간이 맞음. DXGI_FORMAT_R16G16B16A16_FLOAT또한 선형공간임)

 

어쨌든 이러한 이유로 CRT감마가 자동으로 적용되니 이걸 보정해주는 과정이 필요합니다.

바로 1/2.2의 제곱을 다시 곱해줘서 보정해주는 것이죠. CRT감마는 2.2, 역은 1/2.2로 둘을 곱하면 1이 됩니다. 

 

하지만 백버퍼의 특성에 따라 다른데, 백버퍼의 포맷이 DXGI_FORMAT_R8G8B8A8_UNORM 라면 CRT감마가 적용돼서 톤매핑 시 gammaCorrection을 적용해야합니다. 반면, 백버퍼의 포맷이 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB나 

DXGI_FORMAT_R16G16B16A16_FLOAT라면 CRT감마가 적용이 되지 않아, 톤 매핑시 gammaCorrection을 할 필요가 없습니다. CRT감마가 적용되는지 아닌지는 운영체제와 GPU 드라이버에 따라 다르니 직접 실험해 보셔야 합니다.

 

좀 더 정확한 이해를 하기 위해서 다음 문제를 맞춰보면 좋을 것 같습니다.

RenderTarget의 포맷이 DXGI_FORMAT_R16G16B16A16_FLOAT(선형공간) 이고 백버퍼의 포맷이 DXGI_FORMAT_R8G8B8A8_UNORM일 때, 픽쉘쉐이더에 임의로 색이 0.0~ 1.0까지 넣었을때 gammaCorrection을 적용 했을 때와 안 했을 때의 차이는 어떻게 나올까요? 

 

1) 감마커렉션을 적용 했을 때 :

=> CRT감마가 적용되어 둘이 상쇄됩니다. 따라서, 0.1과 0.2의 세기가 physical brightness에 맞게 보입니다. 광자의 수가 두배가 됐을때 실제 광자 수 늘어난거에 비해 더 많이 변한것으로 보이죠.

 

2) 감마커렉션을 적용하지 않았을 때 

=> CRT감마가 적용되어, 0.1과 0.2의 차이가 사람의 눈에 자연스레 보이게 됩니다. 광자 수가 늘어난 것을 CRT감마가 보정을 해준것이죠. 

 

 

요점 : 쉐이더에서 계산은 선형인 공간에서 이루어진다. 하지만, 사람의 눈에 자연스레 보이기 위하여 색상 값들은 비선형적이다. 따라서 톤매핑 시 CRT감마가 적용되는 것이 있으니 상황에 맞게 GammaCorrection을 해줘야한다! 

 

 

 

 

더 자세한 정보를 원한다면 다음 링크를 참조하세요

https://learnopengl.com/Advanced-Lighting/Gamma-Correction

 

LearnOpenGL - Gamma Correction

Gamma Correction Advanced-Lighting/Gamma-Correction As soon as we compute the final pixel colors of the scene we will have to display them on a monitor. In the old days of digital imaging most monitors were cathode-ray tube (CRT) monitors. These monitors h

learnopengl.com