Red, green and mud: fixing color mixing in Total Draw
빨강과 초록이 탁해지는 문제: Total Draw의 색 혼합 개선
Total Draw 개발자가 빨강과 초록을 섞을 때 경계가 어둡고 탁해지는 문제를 OKLab 색 공간으로 개선했습니다. 색을 섞는 방식에 따라 결과의 밝기와 붓질 느낌이 달라지는 이유를 설명하고, 연산 비용과 문서 호환성 때문에 레이어 혼합은 기존 방식으로 남긴 배경도 소개합니다.
- 주제
AI 요약
Total Draw의 스머지(smudge), 블렌드(blend), 블러(blur) 도구를 개발하던 중 두 색이 만나는 경계에 어두운 갈색 띠가 생겼습니다. 원인은 대부분의 페인팅 프로그램이 빛의 밝기와 비례하지 않는 sRGB 값을 그대로 평균 내기 때문입니다. sRGB는 사람 눈이 어두운 색의 차이를 더 잘 구분하는 특성을 고려해 밝기 값을 비선형으로 저장합니다. 그래서 저장된 빨강과 초록 값을 단순히 평균 내면 실제 빛을 섞은 결과보다 어둡게 보입니다.
선형광 혼합은 물리적으로 맞지만 붓질 느낌이 달라집니다
문제의 한 가지 해결책은 sRGB 값을 선형광(linear light)으로 디코딩한 뒤 평균을 내고, 다시 sRGB로 인코딩하는 방식입니다. 글에서는 sRGB 표준의 곡선을 설명하며, 단순한 제곱근 근사보다 실제 변환식이 복잡하다고 짚습니다. 선형광 혼합은 빛을 실제로 섞는 계산에 맞지만, 불투명도 50%로 그은 붓자국이 눈에 약 25%처럼 느껴지는 등 페인팅에서 기대하는 밝기와 어긋날 수 있습니다.
Krita처럼 문서 전체를 선형 색 공간으로 처리하면 붓질뿐 아니라 레이어 불투명도와 혼합 모드도 일관된 공간에서 계산할 수 있습니다. 다만 선형 값은 8비트에서 어두운 영역의 단계가 부족해 그라데이션에 밴딩이 생깁니다. 이를 피하려면 16비트나 부동소수점 저장이 필요해 메모리와 파일 크기가 늘어납니다. Total Draw는 레이어를 64×64 픽셀 타일로 나누고 QOI로 압축하며, QOI는 8비트만 지원합니다. 선형 문서로 전환하면 파일 형식 변경도 필요하고, 색 표현이 문서에 고정돼 나중에 방식을 바꾸기 어렵습니다.
OKLab에서 섞고 결과를 다시 저장합니다
개발자는 대안으로 2020년 Björn Ottosson이 만든 지각 기반 색 공간 OKLab을 선택했습니다. OKLab은 색상 차이를 사람이 지각하는 방식에 맞춰 다루면서, sRGB에서 값을 단순 평균 낼 때처럼 빨강과 초록이 탁한 회색이나 갈색으로 흐르지 않도록 합니다. 두 색 사이가 주황과 노랑을 거쳐 이어집니다. CSS의 color-mix()도 기본 혼합 공간으로 OKLab을 사용합니다.
Total Draw는 혼합할 때만 색을 OKLab으로 변환하고, 결과를 기록할 때 원래 색 공간으로 되돌립니다. 변환은 행렬 곱셈 두 번과 세제곱근 계산으로 이뤄집니다. 이 방식은 문서 전체의 저장 형식을 바꾸지 않고도 붓자국과 혼합 도구의 결과를 개선합니다. 대신 붓질 처리 비용이 늘었습니다. 개발자 컴퓨터에서 4K 캔버스 한 번을 가로지르는 붓질은 약 1ms에서 2ms로 두 배가 됐습니다. 스머지, 블렌드, 블러는 이미 셰이더에서 혼합하므로 성능 저하가 없었습니다.
붓질은 기존 GPU 블렌딩 기능만으로 처리하기 어렵습니다. GPU의 기본 혼합은 빠르지만 단순한 합산에 한정되기 때문입니다. Perceptual 모드에서는 셰이더가 타일의 복사본을 읽고 OKLab 계산을 적용합니다. Total Draw는 사용한 타일만 조작해 캔버스를 구성합니다. 레이어 불투명도와 혼합 모드는 아직 기존 방식으로 계산합니다. 화면 표시와 내보내기 때마다 다시 계산하므로 사용자마다 결과가 달라지는 문제를 막으려면 문서 형식에 혼합 설정을 저장해야 합니다. 다만 이 변경은 사용성 문제와 기존 파일 변환 과제를 낳습니다.
선택 가능한 두 혼합 모드와 다음 과제
설정의 ‘Color mixing’에서 Classic과 Perceptual을 고를 수 있으며, 기본값은 Perceptual입니다. 기존 붓질 느낌을 선호하는 사용자를 위해 Classic도 남겼습니다. 아직 CPU에서 실행하는 버킷 채우기와 선택 영역 채우기는 부드러운 경계를 기존 방식으로 혼합합니다. 레이어 불투명도와 혼합 모드를 지각 기반으로 바꾸려면 문서별 설정 저장과 구버전 파일 변환이 필요합니다.
개발자는 디지털 디스플레이의 가산 혼합과 실제 물감의 감산 혼합도 구분합니다. OKLab은 빛을 섞는 방식에 가깝고, 실제 물감처럼 빨강과 초록이 갈색빛 주황으로 섞이는 효과를 재현하지는 않습니다. 물감 혼합을 모사하는 기능은 향후 과제로 언급합니다.
Reddit 반응
- @u/lalaland4711 — 네, 올바르게 처리하는 방식입니다. 오디오 편집기에서 확대했을 때 실제 주파수가 아니라 샘플을 보는 것과 비슷합니다. 확대하면 샘플 사이를 sinc 보간으로 채워야 합니다.
- @u/bschwind — 오디오 편집기를 확대할 때 어떤 화면을 보여줘야 하는지 시각화 자료가 있나요? 궁금해졌습니다. 실제 샘플 지점은 표시하면서 sinc 보간으로 그 사이를 채우면 될까요?
- @u/flying-sheep — 선형 RGB와 OKLab의 차이를 잘 보여주는 설명입니다. 색을 다루는 기술에서 sRGB 값을 순진하게 보간하는 경우가 많은 점이 이상합니다. 처음 플로팅 라이브러리를 썼을 때 Jet 색상표가 좋지 않다는 걸 배웠고, 그 뒤 지각적으로 균일한 cube helix 팔레트를 알게 됐습니다. 요즘 괜찮은 플로팅 라이브러리는 지각적으로 균일한 색상표를 기본으로 씁니다.
- @u/Rupour — sRGB 보간이 오래 표준으로 쓰여서 가장 손쉬운 선택으로 남은 것 같습니다. 글에서 말했듯 CSS의 color-mix()도 이제 기본으로 지각 기반 보간을 사용합니다. 조금씩 바뀌고 있습니다.
- @u/flying-sheep — 맞습니다. 레거시 16진수나 이름으로 지정한 색이 아닌 색 정의도 그라데이션 등에서 기본으로 OKLab 보간을 합니다. 혼란스럽긴 하지만 어디서나 sRGB를 기본으로 쓰는 것보다는 낫습니다.
- @u/ack_error — 이유가 몇 가지 있습니다. 첫째는 성능입니다. sRGB 이미지에서 sRGB 값을 직접 섞는 방식이 가장 빠릅니다. GPU가 sRGB 이미지의 선형 색 혼합도 가속할 수 있지만 항상 쓸 수 있는 것은 아닙니다. 제가 아는 한 OKLab은 어디에서도 하드웨어 가속을 지원하지 않습니다. 둘째, 사람들은 sRGB 혼합의 결과에 익숙합니다. Photoshop과 그 혼합 모드를 이어받은 프로그램들이 그렇게 작동합니다. 선형 색은 안티앨리어싱과 빛 혼합 같은 경우에 더 낫지만, 밝기 그라데이션이나 일부 리샘플링에서는 결과가 좋지 않습니다. OKLab도 차이가 충분히 크지 않아 복잡성을 감수할 가치가 없는 경우가 많습니다.
- @u/flying-sheep — 다른 분야에서의 지적은 고맙습니다. 다만 이미지 소프트웨어에서는 성능보다 결과가 우선이라고 생각합니다. 그리고 여전히 익숙한 sRGB 혼합을 고수한다니 역겹습니다. 웹 기술도 따라잡았으니 이런 방식을 쓸 이유가 없습니다. 취향 문제가 아니라 잘못된 방식입니다. 밝은 빨강과 밝은 초록을 섞어 어두운 색이 나와서는 안 됩니다.
- @u/pocketshape — 좋은 글입니다. 더 나은 링크를 찾지 못했지만 FiftyThree의 Paper 앱 색 혼합이 흥미로웠습니다. 그 글은 색상 선택기의 경우를 다뤘고, 실제 붓자국 혼합에도 썼는지는 모르겠습니다. 색상 선택기, 가산 도구, 감산 도구마다 혼합 계산을 다르게 하는 편이 맞을 수도 있습니다.
- @u/adriano-1370 — Total Draw에서는 혼합 공간을 하나로 정했나요, 아니면 사용자가 바꾸게 했나요? 붓자국과 색상 선택기에서 다른 동작을 원할 수도 있을 것 같습니다.
- @u/TheRealPomax — 색을 이만큼 중요하게 생각한다면 웹사이트도 밝은 테마와 어두운 테마를 인식해야 합니다.
원문: Total Draw / 번역·요약: Trawling