Unity Study

2026-01-08_Gamma Correction & GPU Texture Compression

NyumMa 2026. 1. 8. 16:41

Cpu -> Gpu 데이터의 전달 흐름

 

Cpu에서 Asset을 메모리에 로드

PNG, TGA, JPG 등의 파일을 메모리에 적재한다.

 

엔진 임포터에서 해당 텍스쳐에 대한 색공간을 처리함

sRGB / Linear

 

기본적으로 모니터는 CRT의 역사상 전자총의 전압 세기와 실제 모니터에서 보여지는 밝기가 비선형적 관계이다.

우리는 a와 같은 색상을 기대하지만 모니터의 물리적 특성상 실제로는 b와 같은 값이 나오게 됨.

, 의도하고자 하는 (127,127,127)의 값이 이보다 더 낮은 값으로 나오게 됨

 

따라서 이러한 인지 부조화를 막기 위해 밝기 값이 떨어지는 물리적 색상 값에 대한 역보정 처리된 데이터를 저장해 놓아 이 데이터가 모니터에 출력될 때 물리적으로 밝기가 떨어져도 올바른 색상이 표시되도록 하는 것이 감마 correction이다.

 

기본적으로 우리 인간은 모든 이미지 및 텍스쳐를 sRGB 공간에서 보고 있다는 것을 가정한다.

모니터에서 텍스쳐가 의도된 밝기보다 어둡게 나오게 될 것을 대비하여 기존 텍스쳐에 보통 1/r 값인 1/2.2 를 처리한 텍스쳐 데이터를 저장한 결과를 보고 있는 것

 

Gamma / sRGB / Linear / Normal Map 정리 노트


왜 감마(Gamma)라는 개념이 생겼는가

1. CRT 디스플레이의 물리적 특성

  • CRT는 입력 전압에 선형적으로 밝기가 증가하지 않음
  • 실제 휘도(Luminance)는 대략 전압의 2.2승수로 나타나짐 -> 휘도라고 하는 것은 우리가 눈으로 보는 것이기 때문에 그렇다.
  • ( 대략적인 수치임, 실제로 지수함수적 특성을 완벽하게 갖고 있지 않다)

  • , 선형 신호를 보내면 화면은 어둡게 출력됨

따라서 이를 해결하기 위해 미리 역으로 보정한 신호를 저장/전송하는 방식이 필요해짐


감마 보정(Gamma Correction)이 필요하게 된 이유


CRT 특성의 물리적 문제에 대해서 감마 correction을 설명할 때

인간 시각 특성(명부보다 암부의 밝기 차이에 대한 인식이좋다)에 대한 설명을 하는 이유?

 

감마가 존재하는 이유와 이를 보정하기 위한 형태의 인과관계에 대한 설명의 관점이 다름

구분 설명
존재 이유 1. CRT의 비선형 출력 특성에 의한 결과 -> 원래보다 어둡게 처리됨
2. 현대 모니터에서는 CRT의 아날로그 특성과 달리RGB의 밝기 비를
선형적으로 출력할 수 있게 되었지만 여전히 CRT의 특성을 활용함 
형태 이유 모니터에서 인간 시각의 밝기 인지 특성을 고려한 보상 함수의 고려를 위한 근거

 

최종적으로 Gamma Correction은 옛날에 사용하던 Analog CRT 선형적 전압에 따른

물리적인 밝기 차이에 이유부터 시작하여

 

현대 과학이 발전하여 모니터에 rgb 밝기 비를 선형적으로 출력할 수 있음에도 감마를 계속 사용하는 이유는

인간은 암부의 변화를 명부보다 더 잘 인식한다는 베버의 법칙의 해석에 따라

동일하게 의도적으로 감마 연산 처리를 모니터 하드웨어에서 처리한다. 

 


감마 보정은 꼭 지수함수일 필요는 없음

 

감마 보정은 본질적으로 비선형 시스템을 역보정하는 함수이다.

 

수학적 모델로 지수함수가 선택된 이유로는

  1. CRT 밝기 응답이 지수함수에 가깝게 근사됨
  2. 인간 시각 모델도 power/log 함수로 잘 근사됨
  3. 아날로그/초기 디지털 하드웨어에서 구현이 매우 쉬움
  4. 오차 대비 체감 손실이 적음

즉, 정확한 계산이라기 보다는 의도한대로 결과가 잘 나오기 때문에 사용하는 의사 모델임 


sRGB vs Linear

sRGB는 무엇이 되었든 모니터에서 감마 보정을 통해 처리되는 특성을 고려하여 컴퓨터에서 데이터를 저장할때는 모니터에서 보여지는 색에 대해서 승수의 역수로 데이터를 저장하게됨.(인코딩)

ex)

ALBEDO 텍스쳐가 (0.5,0.5,0.5) 로 보이도록 하는것이 목적이라면 2.2의 역수를 승수로 하여

약 (0.73,0.73,0.73)이 실제 저장공간의 값으로 저장됨

이때의 저장되는 값에 대한 추상적 공간을 sRGB라고 하며 우리가 모니터로 보는 모든 텍스쳐 및 사진 영상들은

sRGB공간에 있는 텍스쳐들을 모니터를 통하여(감마 correction) 보고 있는 것이다


엔진에서 sRGB 옵션(체크박스)의 정확한 의미는

텍스쳐가 sRGB 감마로 인코딩된 색 데이터이므로 샘플링 시 Linear 공간으로 디코딩하라 라는 뜻 

 

동작 흐름 (Albedo 기준)

[텍스쳐 파일]

sRGB 인코딩

       

[Texture Sampler]

sRGB → Linear 디코딩

       

[Shader]

Linear 공간에서 조명 계산 -> 이게 중요함 ,계산할 때 모니터에서 보는 색상의 형태로 변환해서 계산한 다음 다시 감마 처리함

       

[Output]

Linear → sRGB 로다시 인코딩

 

sRGB 인코딩된 텍스쳐모니터 물리 특성으로 디코딩 됨


Normal Map에서의 sRGB 옵션 해제

-> 해당 텍스쳐는 sRGB 인코딩 된 텍스쳐가 아닌 그냥 순수 rgb 값 데이터 그 자체로 보겠다는 것임.

 

RGB = 색 = 방향 벡터를 [0~1] 범위로 패킹한 수치 데이터

:

(0, 0, 1) → (0.5, 0.5, 1.0) -> rgb로 텍스쳐로는 보이나 내재적으로는 벡터를 담고 있는 정보이기 때문에 변환되면 안됨


Normal Map PNG인데, 컴퓨터가 어떻게 아나,

->

파일은 모른다. 엔진만 안다.

  • PNG/JPG/TGA는 의미를 모르는 숫자 덩어리
  • 이건 노멀이다라는 정보는 파일에 없음

그래서 엔진에서:

  • Texture Type = Normal Map
  • Compression = Normalmap
  • sRGB OFF

이런 옵션을 명시적으로 설정해야 함


따라서  Normal Map은 엔진에서 어둡게 보임

 

사진 뷰어 (Windows 사진 앱)

  • 모든 이미지를 sRGB 색 이미지로 가정
  • 감마 적용 후 표시
  • 밝고 선명하게 보임

엔진에서 Normal Map으로 지정

  • sRGB 해석 x
  • Linear 값 그대로 표시
  • 어둡고 탁하게 보임

 

감마 보정은 CRT의 비선형 밝기 출력 문제를 해결하기 위해 도입되었으며,
그 곡선 형태는 현대 모니터의 특성에서도 인간이 암부 밝기 변화에 민감하다는 시지각 특성을 고려해 설계되었다.


sRGB
는 이러한 감마 특성을 포함한 표준 색공간이며,
엔진에서는 색 텍스쳐를 sRGB에서 Linear로 디코딩해 조명 계산을 수행한다.


반면 normal map은 색이 아닌 방향 벡터 데이터이므로 감마 보정을 적용하지 않으며,
이로 인해 화면에서 어둡게 보이지만 계산적으로는 올바른 상태이다.

 


 

sRGB 디코딩은 CPU에서도, VRAM 적재 시에도 일어나지 않는다.
오직 GPU가 텍스쳐를 샘플링하는 순간 에 하드웨어적으로 수행된다.

 

tex.Sample(sampler, uv)

 

 

sRGB 디코딩 안 하는지에 대해 체크를 하게 되면 이러한 정보는 텍스쳐 리소스 포맷의 sRGB 플래그로 전달된다

 

 

GPU는 '노말맵'이라는 정보로 인식하지 않으며 단순

sRGB로에 대한 변환 처리가 되었는지의 포맷만 인식함.

 


 

BC3 BC5 BC7 DXT etc...

 

GPU 압축 포맷이 필요해진 이유

초기 GPUCPU에서 그래픽 장치가 분리되어 DISCRETE GPU로 분리되어 작동

서로 다른 물리적 회로를 가지고 있기 때문에 PCIe16레인을 통해 데이터가 전달됨

텍스쳐 크기가 커질수록 데이터를 전달하는데 있어서 병목 발생

초기 상용 GPU들의 VRAM용량이 작기 때문에 OOM 등이 발생

메모리 fetch가 데이터 연산보다 비싼 작업임

 

PNG, JPG 등은 랜덤 접근이 불가,

è 텍스쳐 임의의 픽셀을 바로 읽을 수 있도록 하기 위함

è 픽셀 쉐이더에서 tex.sample(sampler,uv)할 때 어느 픽셀부터 처리될지 알수 없기 때문에 랜덤 접근이 중요함

è Png는 가변길이 압축 방식, jpg는 비트 스트림 방식이기 때문에 주변 데이터에 의존적임

 

 

Png, jpg를 텍스쳐로 사용할 때 따라서 해당 포맷을 그대로 사용하지 않고 cpu에서 픽셀을 RAW하게 바꾼 다음 GPU에 적재하게 됨

이때 GPU 텍스쳐 압축방식에서 random access를 지원하도록 설계하여 이러한 문제를 해결함

또한 압축을 통해 메모리 대역폭 문제를 해결하고 랜덤 접근 가능하게 함

 

Block Compression (BC)

DirectX Texture Compression (DXT)

 

Dxt는 레거시 네임이고 dx10부터는 BC로 얘기함

이밖에도 S3TC, BPTC/  모바일에서 ETC2 ASTC 등의 포맷들이 있다.

 

GPUSIMD 최적화되어 있는데 GPU에서는 각 스레드가 각기 다른 픽셀을 처리하지만 SIMD 구조로 같은 명령을 한번에 처리할 수 있도록 설계되어 있다.

JPG, PNG 포맷은 데이터 의존적 및 분기가 많기 때문에 SIMD 구조에 적합하지 않으므로 GPU 에서는 별도의 압축 파일을 통해 SIMD 친화적으로 설계해 놓는다.

 

압축 형식을 가변적이지 않은 고정단위로 하고 분기를 사용하지 않기,

비트마스킹 처리로 여러 픽셀들을 한번에 연산하기 쉽게 설계됨

 

이때 압축을 블록 단위로 진행함하여 고정 길이를 압축을 수행한다.

 

기본 단위: 4×4 픽셀 블록