RGB는 거짓말을 하고 있다: 가시광선 스펙트럼을 제대로 렌더링하기 위한 집요한 여정


엔지니어로서 커리어를 쌓다 보면, 가장 기초적이라고 생각했던 개념이 사실은 가장 복잡한 ‘토끼굴(Rabbit hole)‘이었다는 것을 깨닫는 순간이 옵니다. 저에게는 ‘시간(Time)‘과 ‘색상(Color)‘이 바로 그런 주제였습니다.

최근 Hacker News에서 “Rendering the Visible Spectrum” 이라는 글을 읽고, 오랜만에 엔지니어링의 본질적인 즐거움을 느꼈습니다. 이 글은 단순히 무지개를 그리는 법에 대한 튜토리얼이 아닙니다. 물리학, 생물학, 그리고 지각 심리학이 얽힌 복잡한 문제를 해결하기 위해 밑바닥부터 파고드는 집요한 탐구 일지입니다.

오늘은 이 아티클을 바탕으로, 왜 우리가 모니터에서 보는 스펙트럼 이미지가 대부분 ‘가짜’인지, 그리고 이를 제대로 구현하려면 어떤 기술적 난관을 넘어야 하는지 Deep Dive 해보겠습니다.

1. 구글 이미지 검색의 거짓말

구글에 “visible spectrum”을 검색해 보십시오. 대부분의 이미지는 빨주노초파남보가 뚜렷한 경계(banding)를 가지고 나뉘어 있거나, 밝기가 균일하지 않습니다. 마치 만화에 나오는 무지개처럼 말이죠.

하지만 실제 프리즘이나 회절 격자(diffraction grating)를 통해 본 스펙트럼은 그렇지 않습니다. 색은 경계 없이 부드럽게 이어지며, 특정 파장대에서는 우리 눈의 민감도에 따라 밝기가 급격히 변합니다. 인터넷에 떠도는 대부분의 이미지는 물리학적으로 틀렸습니다.

이 글의 저자 Brandon Li는 이 불편한 진실을 마주하고, 직접 코드를 짜서 “물리학적으로, 그리고 지각적으로 가장 정확한 스펙트럼”을 렌더링하기로 결심합니다.

2. 파장을 RGB로 변환하는 것의 함정

단순히 생각하면, 특정 파장($\lambda$)을 RGB 값으로 매핑하면 될 것 같습니다. 하지만 여기엔 거대한 장벽이 있습니다.

Grassmann의 법칙과 CIE 1931

색은 스펙트럼 파워 분포(SPD)에 의해 결정되지만, 우리 눈은 이를 3가지 원추세포(Cone cells)로 압축해서 받아들입니다. 이를 수학적으로 모델링한 것이 CIE 1931 색 공간입니다. 문제는 순수한 단색광(Monochromatic light, 스펙트럼상의 색)은 RGB 색 공간의 Gamut(표현 가능 영역) 바깥 에 존재한다는 점입니다.

RGB 값은 0과 1 사이여야 하는데, 스펙트럼상의 순수한 색을 그대로 변환하면 음수나 1을 초과하는 값이 튀어나옵니다. 여기서 엔지니어링적 타협이 필요합니다.

“어떻게 Gamut 밖의 색을 안으로 끌고 들어올 것인가?”

저자는 여러 가지 방법을 시도합니다:

  1. 단순 클리핑: 색 정보가 손실됨.
  2. 회색(Gray) 섞기: 채도를 낮춰서 Gamut 안으로 억지로 밀어 넣기.

가장 합리적인 방법은 스펙트럼 색상에 회색을 섞어 채도를 낮추는 것입니다. 하지만 여기서 색채학의 끝판왕, Abney Effect 가 등장합니다.

3. Abney Effect: 파란색에 흰색을 섞으면 보라색이 된다?

이 부분이 이 아티클의 하이라이트입니다. 이론적으로 파란색($460nm$)에 무채색(회색)을 섞으면 ‘연한 파란색’이 되어야 합니다. 하지만 우리 뇌는 이를 보라색(Violet) 으로 인식합니다. 채도가 변할 때 색상(Hue)이 변해 보이는 현상, 이것이 바로 Abney Effect 입니다.

저자가 초기에 렌더링한 스펙트럼에서 $420nm \sim 450nm$ 구간이 실제보다 보랏빛으로 보이는 문제가 발생했습니다. 일반적인 개발자라면 “이게 이론상 맞는 값이니까” 하고 넘어갔을 겁니다. 하지만 저자는 이를 해결하기 위해 “Effective Wavelength” 라는 개념을 도입해 수동 보정을 감행합니다.

  • CIE 색도 다이어그램(Chromaticity Diagram)에서 등색상 곡선(Equal hue curve)을 추적.
  • 회색을 섞었을 때 원래 파장의 색상(Hue)을 유지하도록 파장 값을 인위적으로 시프트(Shift).

이 과정은 CIECAM02 같은 복잡한 Color Appearance Model을 사용하면 자동화할 수 있지만(Hacker News 댓글에서도 Python의 colour 패키지를 추천하더군요), 저자는 이를 기하학적으로 직접 풀어냈습니다. 저는 이런 “바퀴를 다시 발명하는” 접근을 매우 좋아합니다. 그래야 바퀴가 굴러가는 원리를 뼈저리게 이해할 수 있으니까요.

4. Gamma Correction: 잊혀진 영웅

또 하나 흥미로운 점은 감마 보정(Gamma Correction) 입니다. Hacker News의 한 유저는 “감마 보정이 글의 후반부에 각주처럼 다뤄진 것이 놀랍다”고 지적했습니다.

“우리의 눈은 밝기를 비선형적으로 인식합니다. 어두운 영역의 변화에 훨씬 민감하죠. 선형 RGB 공간에서 계산된 값을 모니터에 그대로 쏘면, 중간 톤이 다 망가집니다.”

많은 그래픽스 입문자가 $(R+G)/2$ 같은 실수를 저지릅니다. 정확한 블렌딩을 위해서는 Linear RGB로 변환 -> 연산 -> 다시 sRGB(Gamma encoding)로 변환 하는 과정을 거쳐야 합니다. 이 글의 저자는 다행히 이 부분을 놓치지 않았고, 덕분에 스펙트럼의 그라데이션이 매우 부드럽게 표현되었습니다.

5. 결과물: 원소 주기율표의 재해석

이 모든 삽질의 결과물은 단순한 무지개 이미지를 넘어, “원소 스펙트럼 주기율표” 로 이어졌습니다. NIST(미국 국립표준기술연구소) 데이터를 가져와서, 각 원소가 방출하는 스펙트럼 라인을 위에서 만든 렌더링 엔진으로 그려낸 것이죠.

특히 헬륨(He)이나 네온(Ne)의 방전관 사진과 렌더링 된 이미지를 비교한 부분은 전율이 돋습니다. 이론(코드)과 실제(사진)가 일치할 때의 쾌감이랄까요. 저자는 DCI-P3 광색역 프로필까지 적용하여 최신 디스플레이에서의 경험까지 최적화했습니다.

6. 마치며: “Good Enough”를 넘어서

우리는 종종 “이 정도면 됐지”라는 생각으로 개발합니다. 인터넷에 널린 부정확한 스펙트럼 이미지들도 그런 타협의 산물일 것입니다. 하지만 누군가는 그 부정확함에 불편함을 느끼고, 논문을 뒤지고, 수식을 검증하여 “진짜”를 만들어냅니다.

이 프로젝트는 오픈소스로 공개되어 있습니다. 만약 여러분이 데이터 시각화나 그래픽스에 관심이 있다면, 단순히 라이브러리를 가져다 쓰는 것을 넘어 “색(Color)“이라는 데이터가 인간의 뇌까지 도달하는 파이프라인 을 한 번쯤 깊게 파보시길 권합니다.

요약:

  • 모니터의 RGB는 실제 자연광을 100% 재현할 수 없다.
  • 스펙트럼을 그릴 때는 Gamut 매핑과 지각적 보정(Abney Effect)이 필수다.
  • 제대로 된 엔지니어링은 ‘눈에 보이는 대로’가 아니라 ‘뇌가 느끼는 대로’ 구현하는 것이다.

References: