Linear Workflow가 필요한 이유: CG의 빛은 이렇게 계산된다

    리니어 워크플로우 썸네일

    왜 리니어 워크플로 이야기가 필요할까

    VFX나 3D 렌더링을 하다 보면 “리니어 워크플로(Linear Workflow)”라는 말을 자주 듣게 됩니다. 결론부터 말하면, 이건 CG의 빛을 실제 물리 법칙에 맞게 계산하기 위한 필수 규칙이에요. 이 규칙을 안 지키면 조명은 뿌옇게 뜨고, 합성 엣지에는 이상한 테두리가 생기고, 하이라이트는 뭉개져 버립니다. 왜 이런 일이 벌어지는지, 그리고 어떻게 해결하는지 하나씩 풀어볼게요.

    빛은 원래 더하기로 계산된다 (물리 법칙 이해하기) 💡

    먼저 아주 단순한 사실 하나를 짚고 가야 해요. 현실 세계의 빛은 **선형(linear)**으로 더해집니다. 촛불 하나가 있는 방에 똑같은 촛불을 하나 더 켜면, 그 방의 밝기(에너지)는 정확히 2배가 됩니다. 촛불 두 개가 세 개, 네 개가 되어도 마찬가지예요. 빛의 양은 단순히 산술적으로 더해지는 물리량입니다.

    CG 렌더러가 조명을 계산할 때도 이 원리를 그대로 따라야 합니다. 면 하나에 빛 A가 0.3만큼, 빛 B가 0.4만큼 도달한다면 최종 밝기는 0.7이어야 물리적으로 맞는 결과예요. 렌더러 내부의 모든 연산 — 그림자 감쇠, 반사, 굴절, 블러, 안티앨리어싱 — 은 전부 이 “더하기가 성립하는” 선형의 숫자 공간에서 이루어져야 정확합니다.

    문제는, 우리가 렌더러에 입력하는 텍스처 이미지들은 대부분 이 선형 상태가 아니라는 점이에요.

    감마가 걸린 텍스처로 렌더링하면 생기는 문제

    여기서 앞선 글에서 다룬 “감마”가 등장합니다. 감마란 쉽게 말해 이미지 파일 안에 밝기 값을 왜곡해서 저장하는 방식이에요. 우리 눈이 어두운 영역의 미묘한 차이를 더 잘 구분하기 때문에, 일반적인 이미지 포맷(JPG, PNG, 대부분의 sRGB 텍스처)은 어두운 부분에 더 많은 정보를 몰아주는 방식으로 밝기 값을 압축해서 저장합니다. 이렇게 저장된 숫자는 실제 빛의 양과 비례하지 않아요.

    문제는 이 왜곡된 숫자를 “이게 실제 빛의 양이다”라고 착각하고 그대로 더하기 연산을 해버리면 완전히 틀린 결과가 나온다는 겁니다. 대표적인 예시를 볼게요.

    0.5 + 0.5 예시

    • 선형 공간(물리적으로 올바른 상태)에서 밝기 0.5인 빛 두 개를 더하면: 0.5 + 0.5 = 1.0 (정확히 2배 밝아짐, 물리 법칙과 일치)
    • 감마가 걸린 상태(예: sRGB 인코딩된 값)에서 똑같은 숫자 0.5와 0.5를 그대로 더하면: 수학적으로는 1.0이 나오지만, 이 값을 다시 감마 디코딩해서 실제 빛의 양으로 환산하면 원래 의도했던 2배보다 훨씬 더 밝은 결과가 나옵니다.

    즉 감마가 걸린 상태에서 더하기, 곱하기, 블러 같은 연산을 하면 결과값이 실제 물리 법칙과 어긋나 버립니다. 그런데 렌더러 안에서 일어나는 조명 계산, 안티앨리어싱, 모션 블러, 디퓨즈 블러링은 전부 이런 덧셈·평균 연산의 집합이에요. 그러니 감마 걸린 텍스처를 그대로 렌더러에 넣고 계산하면, 조명이 물리적으로 말이 안 되는 방향으로 어긋나게 되는 거죠.

    리니어 워크플로의 전체 파이프라인 구조

    그래서 실무에서는 다음과 같은 3단계 파이프라인을 지킵니다.

    [입력 변환] → [리니어 공간에서 렌더링] → [출력 변환]
    • 입력 변환(Input Transform): 디퓨즈 컬러 텍스처처럼 사람 눈으로 색을 고른 이미지(sRGB로 인코딩된 파일)를 렌더러에 넣기 직전에 감마를 제거해서 선형 값으로 되돌립니다. 반대로 노멀맵, 러프니스맵처럼 애초에 감마가 걸려있지 않은 데이터 텍스처는 이 과정 없이 원본 숫자 그대로(Raw) 읽어야 해요.
    • 리니어 렌더(Linear Render): 렌더러 내부의 모든 조명 계산, 그림자, 반사, 블러 연산은 선형 공간에서 이루어집니다. 이 단계가 바로 앞서 설명한 “빛의 물리 법칙”이 지켜지는 구간이에요.
    • 출력 변환(Output Transform): 계산이 끝난 선형 결과 이미지는 사람 눈이나 모니터가 인식하기 좋은 형태가 아니기 때문에, 최종적으로 모니터에 보여주거나 파일로 저장할 때 다시 감마(또는 디스플레이용 톤매핑)를 입혀서 보여줍니다.

    정리하면 “감마는 입구와 출구에서만 다루고, 중간 계산 과정은 전부 선형으로 한다”는 게 리니어 워크플로의 핵심 원칙입니다.

    단계상태하는 일
    입력 변환감마 인코딩 → 선형으로 디코딩컬러 텍스처의 감마를 제거
    리니어 렌더선형 (물리 단위)조명, 그림자, 블러, 합성 연산
    출력 변환선형 → 감마(또는 디스플레이 변환)모니터/파일용으로 재인코딩

    HDR와 부동소수점(EXR)이 필요한 이유

    리니어 워크플로를 실제로 구현하려면 파일 포맷도 뒷받침이 되어야 합니다. 일반적인 8비트 JPG나 PNG는 0~255 사이의 정수값만 저장할 수 있어요. 그런데 선형 공간에서는 밝은 영역(하이라이트, 광원)의 값이 1.0을 훌쩍 넘어서 수십, 수백 배까지 올라갈 수 있습니다. 태양광은 실내 조명보다 몇 자릿수는 더 밝으니까요.

    이걸 8비트 정수로 담으려고 하면 밝은 부분은 전부 255에서 잘려버리는 “타버린(clipped)” 상태가 됩니다. 그래서 HDR(High Dynamic Range), 즉 1.0을 넘는 값도 표현할 수 있고 소수점 단위로 세밀하게 밝기를 저장할 수 있는 부동소수점(floating point) 포맷이 필요합니다.

    • EXR 파일: VFX 업계 표준 포맷으로, 보통 16bit half float 방식을 씁니다. 이름 그대로 원래 32bit(float)의 절반 크기지만, 실무에서 필요한 정밀도와 넓은 밝기 범위(다이내믹 레인지)를 충분히 담을 수 있어서 널리 쓰여요.
    • 32bit full float: 더 높은 정밀도가 필요한 경우(정밀한 컴포지팅 연산, 깊이 채널 등)에 사용합니다. 용량은 더 크지만 계산 오차가 거의 없습니다.

    이런 포맷이 있어야 렌더링 결과에 담긴 실제 빛의 양(예: 태양광 1000, 촛불 0.1처럼 극단적으로 차이 나는 값)을 손실 없이 그대로 저장하고, 나중에 컴포지팅 단계에서 노출을 조절하거나 톤매핑을 적용할 수 있는 여유가 생깁니다.

    감마 보정, 언제 어디서 해야 할까

    정리하자면 감마를 만지는 타이밍은 딱 두 곳뿐이에요.

    • 입력할 때: sRGB로 색을 고른 컬러/디퓨즈 텍스처를 불러올 때 감마를 제거(선형화)합니다.
    • 출력할 때: 최종 렌더 결과를 모니터에 띄우거나 클라이언트에게 전달할 파일로 내보낼 때, 디스플레이에 맞는 감마(또는 ACES 같은 컬러 매니지먼트의 뷰 트랜스폼)를 입힙니다.

    반대로 하지 말아야 할 것은 다음과 같습니다.

    • 노멀맵, 러프니스맵, 메탈릭맵, 디스플레이스먼트맵처럼 색이 아니라 수치 데이터를 담은 텍스처에 감마를 적용하는 것 (이건 Raw로 읽어야 해요 — 이 주제는 시리즈 뒤에서 더 자세히 다룹니다)
    • 렌더링 중간 과정(라이팅, 블러, 합성의 곱하기·더하기 연산)에서 감마가 걸린 상태로 연산하는 것
    • 이미 감마가 입혀진 최종 이미지에 또 한 번 감마를 입히는 이중 보정(더블 감마)

    리니어 워크플로를 안 지켰을 때 나타나는 대표 증상

    리니어 워크플로가 깨지면 눈으로 봐도 티가 나는 문제들이 생깁니다. 대표적인 증상 세 가지를 알아두면 트러블슈팅에 큰 도움이 돼요.

    • 뿌옇고 밋밋한 그림자: 감마가 걸린 상태로 그림자 감쇠를 계산하면 어두운 영역의 대비가 뭉개져서, 그림자가 또렷하지 않고 안개가 낀 것처럼 뿌옇게 나옵니다.
    • 오브젝트 엣지에 이상한 색 테두리(할레이션/프린징): 안티앨리어싱이나 합성 시 엣지 부분의 픽셀 블렌딩이 선형이 아닌 상태에서 이루어지면, 배경과 전경이 만나는 경계에 원래 없던 색 띠나 밝은 테두리가 생깁니다.
    • 하이라이트가 뭉개지고 타버림: 8비트 정수 포맷이나 감마가 걸린 상태로 밝은 광원, 반사 하이라이트를 처리하면 값이 클리핑되어 디테일 없이 하얗게 날아가 버립니다. HDR/플로트 포맷과 선형 연산이 뒷받침되어야 하이라이트의 미묘한 그러데이션이 살아납니다.

    이런 증상이 보인다면 텍스처의 컬러 스페이스 설정, 렌더러의 출력 변환 설정, 그리고 사용 중인 파일 포맷이 8비트인지 float인지부터 점검해보는 게 좋습니다.

    자주 묻는 질문(FAQ)

    Q1. 리니어 워크플로를 안 쓰면 렌더링 자체가 안 되나요? 아니요, 렌더링 자체는 됩니다. 다만 결과물이 물리적으로 부정확해서 조명이 실제 사진처럼 자연스럽게 나오지 않고, 합성 시 배경 플레이트와 CG 요소가 잘 안 어우러지는 문제가 생깁니다. 그래서 사실적인 VFX·라이팅 작업에서는 사실상 필수로 여겨집니다.

    Q2. 8비트 텍스처를 써도 리니어 워크플로가 가능한가요? 네, 가능합니다. 리니어 워크플로는 파일 비트 심도보다는 “연산이 선형 공간에서 이루어지는가”가 핵심이에요. 다만 8비트 정수 텍스처는 어두운 영역에서 계단 현상(밴딩)이 생기기 쉬우므로, 가능하면 16bit 이상이나 float 포맷을 쓰는 게 품질에 유리합니다.

    Q3. ACES를 쓰면 리니어 워크플로를 따로 신경 안 써도 되나요? ACES는 리니어 워크플로 개념을 표준화하고 자동화해주는 색관리 체계예요. 입력·출력 변환 규칙을 ACES가 대신 관리해주기 때문에 실수는 줄어들지만, 텍스처의 컬러 스페이스를 올바르게 지정하는 등 기본 개념은 여전히 이해하고 있어야 제대로 활용할 수 있습니다.

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다