HDR 디스플레이 색역 클리핑과 과도한 하이라이트를 자동 검수하는 아트 QA

HDR 디스플레이에서 색역 클리핑과 과도한 하이라이트를 자동 검수하는 방법을 설명합니다. PQ 기반 니트 측정, 히트맵, 임계값 정책, 셰이더·캡처 파이프라인으로 아트 QA를 CI에 연결하고 HDR10과 실제 디스플레이 기준의 차이까지 다룹니다.

✓ 복사 완료!
챕터자동화 테스트 & 회귀 검증
난이도중급
상태● 검토 완료
대상 엔진
Engine Agnostic
최종 업데이트
HDR 디스플레이 색역 클리핑과 과도한 하이라이트를 자동 검수하는 아트 QA

핵심 요약

HDR 아트 QA는 화면의 최종 출력값을 기준으로 색역 이탈과 하이라이트 과다 노출을 수치화해야 합니다. HDR10의 PQ(ST 2084) 신호를 절대 휘도인 니트로 변환하고 출력 RGB의 클리핑 비율과 임계 휘도 초과 면적을 프레임별로 검사하면 사람이 모든 장면을 직접 확인하지 않아도 위험한 아트를 찾을 수 있습니다.

핵심은 saturate()나 톤 매핑으로 문제가 숨겨지기 전에 중간값을 측정하고 UI·블룸·하늘처럼 의도적으로 밝은 영역은 AOV, 스텐실 또는 머티리얼 태그로 별도 정책을 적용하는 것입니다.

HDR 아트 QA에서 무엇을 검사해야 하는가?

HDR 화면에서는 단순히 RGB 값이 밝은지만 확인해서는 부족합니다. 다음 세 가지를 분리해 검사해야 합니다.

검사 항목측정 대상대표적인 실패 신호권장 결과
색역 이탈타깃 색공간의 선형 RGB한 개 이상의 채널이 0 미만 또는 1 초과색상 보정, 색역 매핑, 머티리얼 수정
하드 클리핑톤 매핑 이후 출력 코드값여러 픽셀이 최대 코드값에 고착톤 매핑 커브와 노출 재검토
과도한 하이라이트PQ를 복원한 절대 휘도지정 니트 이상 영역이 넓거나 지속됨발광값, 노출, 라이트 강도 조정

여기서 색역 이탈과 하드 클리핑은 같은 문제가 아닙니다. 색역 이탈은 표현 가능한 색 삼원색 범위를 벗어난 상태이고 하드 클리핑은 그 값을 강제로 0 또는 1에 붙여 디테일을 잃는 상태입니다. 색역 매핑을 통해 이탈을 해결했더라도 최종 출력에서 하드 클리핑이 발생할 수 있습니다.

왜 HDR 하이라이트는 RGB 값만으로 판단하면 안 되는가?

HDR10은 일반적으로 ST 2084 PQ 인코딩과 BT.2020 컨테이너를 사용합니다. PQ의 코드값은 선형 밝기가 아니므로 0.8이 0.4의 두 배 밝다는 뜻이 아닙니다. 최종 출력의 밝기를 비교하려면 PQ EOTF로 코드값을 니트로 변환해야 합니다.

PQ 복원식은 다음과 같습니다.

L=10000(max⁡(V1/m2−c1,0)c2−c3V1/m2)1/m1L = 10000 \left( \frac{\max\left(V^{1/m_2}-c_1, 0\right)}{c_2-c_3V^{1/m_2}} \right)^{1/m_1}

여기서 V는 0부터 1까지 정규화한 PQ 코드값이며 상수는 ST 2084 기준으로 다음과 같습니다.

m1=261016384,m2=252332,c1=34244096,c2=2413128,c3=2392128m_1=\frac{2610}{16384}, \quad m_2=\frac{2523}{32}, \quad c_1=\frac{3424}{4096}, \quad c_2=\frac{2413}{128}, \quad c_3=\frac{2392}{128}

따라서 자동 검수기는 10비트 코드값을 그대로 비교하지 말고 다음 순서로 처리해야 합니다.

  1. 10비트 PQ 코드를 code / 1023.0으로 정규화합니다.
  2. ST 2084 PQ EOTF를 적용해 니트로 변환합니다.
  3. 프로젝트의 기준 휘도와 비교합니다.
  4. 임계값을 넘은 픽셀의 면적과 연결 영역을 계산합니다.

색역 클리핑은 어떻게 감지하는가?

검사 기준은 최종 디스플레이 색공간으로 변환된 선형 RGB입니다. 예를 들어 렌더러가 ACEScg 또는 Rec.2020 선형 공간에서 작업한다면 XYZ를 거쳐 목표 색공간으로 변환한 뒤 각 채널을 확인합니다.

rgbtarget=MXYZ→targetXYZ\mathbf{rgb}_{target}=M_{XYZ\rightarrow target}\mathbf{XYZ}

다음 조건을 만족하면 색역 이탈로 표시할 수 있습니다.

outOfGamut(p)=(min⁡(rgbtarget(p))<−ϵ)∨(max⁡(rgbtarget(p))>1+ϵ)\text{outOfGamut}(p)=\left(\min(\mathbf{rgb}_{target}(p)) < -\epsilon\right) \lor \left(\max(\mathbf{rgb}_{target}(p)) > 1+\epsilon\right)

epsilon은 부동소수점 오차를 위한 여유값입니다. 보통 0.001에서 시작하되 렌더러의 색변환 정밀도와 캡처 포맷에 맞춰 조정합니다.

중요한 점은 색역 검사를 수행하기 전에 클램프하지 않는 것입니다. 다음처럼 측정 전에 saturate()를 적용하면 모든 문제가 정상 범위로 보입니다.

// 잘못된 순서: 이탈 정보를 잃는다.
float3 clippedRgb = saturate(targetRgb);

// 올바른 순서: 클램프 전에 검사한다.
float outOfGamut =
    any(targetRgb < -_GamutEpsilon) ||
    any(targetRgb > 1.0 + _GamutEpsilon);
float3 displayRgb = saturate(targetRgb);

엔진의 최종 톤 매핑 패스가 색역 매핑을 수행한다면 두 지점을 모두 검사하는 것이 좋습니다.

  • 톤 매핑 전: 발광 머티리얼과 라이트 입력 자체의 문제 탐지
  • 톤 매핑 후: 실제 디스플레이 출력에서 남은 클리핑 탐지

HDR 출력에서 색역 이탈과 하이라이트 클리핑을 서로 다른 마스크로 표시한 아트 QA 히트맵

과도한 하이라이트 임계값은 어떻게 정하는가?

모든 밝은 픽셀을 실패로 처리하면 태양, 폭발, 번개, UI 알림까지 오탐으로 분류됩니다. 임계값은 프로젝트의 디스플레이 목표와 콘텐츠 역할을 함께 반영해야 합니다.

다음은 HDR10 1000니트 마스터를 가정한 예시 정책입니다. 절대적인 표준값이 아니라 자동 검수를 시작하기 위한 프로젝트 설정값입니다.

display_peak_nits: 1000
reference_white_nits: 203
highlight_warn_nits: 800
highlight_fail_nits: 1000
max_highlight_area_ratio: 0.005
max_persistent_frames: 3
near_clip_code: 0.995
gamut_fail_ratio: 0.001

reference_white_nits는 일반적인 HDR 기준 백색점으로 사용할 수 있지만 프로젝트의 색관리 파이프라인에 따라 달라집니다. highlight_fail_nits도 디스플레이 피크가 600니트인지 4000니트인지에 따라 달라져야 합니다.

실무에서는 단일 픽셀의 최대값보다 다음 지표를 함께 기록하는 편이 안정적입니다.

지표의미활용
max_nits프레임의 최고 휘도순간적인 스파크와 폭발 확인
p99.9_nits상위 0.1% 픽셀의 휘도전체적인 하이라이트 과다 노출 확인
highlight_area_ratio임계값 초과 픽셀 비율넓은 면적의 과노출 확인
persistent_frames연속 초과 프레임 수장시간 눈부심과 플리커 확인
near_clip_ratio최대 코드값 근처 픽셀 비율톤 매핑 포화 확인

자동 검수 파이프라인은 어떻게 구현할까?

1단계: 동일한 렌더링 조건으로 HDR 캡처하기

검수 입력은 일반 SDR 스크린샷이 아니라 HDR 메타데이터를 보존한 출력이어야 합니다. 가능한 경우 다음 정보를 함께 저장합니다.

  • 캡처 포맷: 16비트 또는 32비트 부동소수점 EXR, 혹은 PQ 기반 HDR 프레임
  • 색공간: Rec.2020, P3-D65, ACEScg 등
  • EOTF: ST 2084 PQ 또는 HLG
  • 기준 백색과 디스플레이 피크 휘도
  • 노출값, 카메라 컷, 프레임 번호, 씬 및 머티리얼 ID

OS의 데스크톱 캡처는 운영체제의 HDR 보정이나 디스플레이 톤 매핑이 개입할 수 있으므로 렌더러 내부의 출력 패스 또는 테스트 전용 캡처 패스를 사용하는 편이 재현성이 높습니다.

2단계: 색역·클리핑·휘도 마스크 만들기

다음은 PQ 프레임을 검사하는 Python과 NumPy 기반의 참고 코드입니다. 입력 배열은 float32 타입의 H x W x 3 형태이며 각 채널은 0부터 1 사이의 정규화된 PQ 코드값이라고 가정합니다.

import numpy as np


def pq_to_nits(code):
    m1 = 2610.0 / 16384.0
    m2 = 2523.0 / 32.0
    c1 = 3424.0 / 4096.0
    c2 = 2413.0 / 128.0
    c3 = 2392.0 / 128.0

    value = np.clip(code, 0.0, 1.0)
    powered = np.power(value, 1.0 / m2)
    numerator = np.maximum(powered - c1, 0.0)
    denominator = c2 - c3 * powered
    return 10000.0 * np.power(numerator / denominator, 1.0 / m1)


def inspect_hdr_frame(pq_rgb, highlight_nits=800.0, fail_nits=1000.0):
    channel_nits = pq_to_nits(pq_rgb)
    pixel_nits = np.max(channel_nits, axis=2)

    highlight_mask = pixel_nits >= highlight_nits
    fail_mask = pixel_nits >= fail_nits
    near_clip_mask = np.any(pq_rgb >= 0.995, axis=2)

    pixel_count = pq_rgb.shape[0] * pq_rgb.shape[1]
    return {
        'max_nits': float(np.max(pixel_nits)),
        'p99_9_nits': float(np.percentile(pixel_nits, 99.9)),
        'highlight_area_ratio': float(np.mean(highlight_mask)),
        'fail_area_ratio': float(np.mean(fail_mask)),
        'near_clip_ratio': float(np.mean(near_clip_mask)),
        'highlight_mask': highlight_mask,
        'fail_mask': fail_mask,
        'near_clip_mask': near_clip_mask,
        'pixel_count': pixel_count,
    }

이 코드는 하이라이트 밝기를 측정하는 예시입니다. 색역 이탈 검사는 PQ 코드값이 아니라 톤 매핑 전의 타깃 선형 RGB 또는 XYZ 변환 결과를 사용해야 합니다. 이미 PQ로 인코딩된 값에서 RGB 채널이 1에 가깝다는 사실만으로는 색역 이탈 여부를 정확히 판단할 수 없습니다.

3단계: 영역별 정책과 지속 시간 적용하기

전체 프레임의 평균값만 보면 폭발 이펙트와 캐릭터 얼굴의 과노출을 구분할 수 없습니다. 렌더 패스에서 다음과 같은 영역 마스크를 함께 출력합니다.

영역 태그기본 정책 예시
CharacterFace800니트 초과 면적을 엄격하게 검사
EmissiveFX높은 피크를 허용하되 지속 프레임을 제한
SunDisk최대 휘도는 허용하고 주변 클리핑만 검사
UI별도의 SDR/HDR UI 정책 적용
Sky넓은 영역의 클리핑 비율을 검사
Unknown기본 실패 정책 적용

프레임 단위 검사에 더해 persistent_frames를 계산하면 카메라가 잠깐 바라본 폭발과 계속 화면을 차지하는 발광 간판을 구분할 수 있습니다. 예를 들어 1000니트 초과 영역이 3프레임 이상 연속되고 면적 비율이 0.5%를 넘으면 실패로 분류할 수 있습니다.

4단계: CI에서 실패 원인을 바로 추적하기

아트 QA 결과는 단순한 성공·실패보다 수정 가능한 정보여야 합니다. 최소한 다음 데이터를 저장합니다.

{
  "scene": "Arena_Night",
  "camera": "Shot_014",
  "frame": 248,
  "max_nits": 1248.6,
  "p99_9_nits": 932.4,
  "highlight_area_ratio": 0.0081,
  "near_clip_ratio": 0.012,
  "gamut_fail_ratio": 0.0034,
  "top_regions": [
    {"id": "FX_Explosion_03", "area_ratio": 0.0062},
    {"id": "Material_Sign_17", "area_ratio": 0.0011}
  ],
  "artifacts": [
    "capture.exr",
    "highlight-mask.webp",
    "gamut-mask.webp"
  ]
}

대시보드에는 원본 프레임, 하이라이트 마스크, 색역 마스크, 이전 기준선과의 차이를 함께 보여주는 것이 좋습니다. 아티스트가 결과를 열었을 때 어느 머티리얼과 어느 프레임을 수정해야 하는지 바로 알 수 있어야 합니다.

히트맵만으로는 부족한 이유는 무엇인가?

히트맵은 공간 정보를 보여주지만 색의 의도와 시간 변화를 설명하지 못합니다. 다음 검사를 함께 사용해야 합니다.

  • 연결 요소 분석: 작은 스파크인지 넓은 면적의 간판인지 구분
  • 프레임 지속성: 순간적인 효과인지 장시간 노출인지 확인
  • 머티리얼 ID 조회: 문제가 된 셰이더와 텍스처 추적
  • 카메라 컷별 기준선 비교: 같은 샷의 이전 승인 결과와 비교
  • 블룸 전후 비교: 블룸 자체가 아니라 원본 하이라이트가 과도한지 확인

특히 블룸이 켜진 최종 화면만 검사하면 밝은 영역이 주변으로 확장되어 실제 발광값보다 큰 영역이 실패할 수 있습니다. 따라서 원본 HDR 컬러, 톤 매핑 출력, 블룸 합성 출력의 세 지점을 별도로 캡처하면 원인을 더 빠르게 분리할 수 있습니다.

색역 클리핑과 하이라이트 과다를 함께 판정하는 기준

최종 판정은 여러 지표를 조합합니다.

Fail=(rgamut>rgamutmax)∨(rhighlight>rhighlightmax∧fpersistent≥fmax)∨(rnearClip>rnearClipmax)\text{Fail}=\left(r_{gamut}>r_{gamut}^{max}\right) \lor \left(r_{highlight}>r_{highlight}^{max}\land f_{persistent}\geq f_{max}\right) \lor \left(r_{nearClip}>r_{nearClip}^{max}\right)

여기서 r_gamut은 색역 이탈 픽셀 비율이고 r_highlight는 임계 니트 초과 면적 비율입니다. 단, 이 공식은 기본적인 게이트 예시일 뿐입니다. 폭발이나 태양처럼 의도된 효과는 예외 목록보다 영역별 정책과 머티리얼 태그를 사용하는 편이 유지보수에 유리합니다.

권장 판정 단계

  1. Unknown 영역에서 색역 이탈과 하드 클리핑을 우선 검사합니다.
  2. 영역별 하이라이트 임계값과 최대 면적 비율을 적용합니다.
  3. 연속 프레임 수와 카메라 컷을 반영합니다.
  4. 실패 프레임과 마스크를 아트 리뷰 도구에 업로드합니다.
  5. 승인된 기준선과 비교해 새로 발생한 문제만 알립니다.

자주 묻는 질문 (FAQ)

HDR 검수에서 1000니트를 항상 실패로 처리해야 하나요?

아닙니다. 디스플레이 피크, 콘텐츠 역할, 노출 지속 시간에 따라 달라집니다. 프로젝트 기준 백색과 디스플레이 목표 휘도를 먼저 정한 뒤 영역별 임계값을 설정해야 합니다.

PQ 캡처와 EXR 캡처 중 무엇을 사용해야 하나요?

최종 디스플레이 출력을 검증하려면 PQ 캡처가 유용하고 셰이더·톤 매핑·발광 입력의 원인을 추적하려면 부동소수점 EXR이 유리합니다. 가능하면 두 포맷을 같은 프레임에서 함께 저장합니다.

색역 이탈을 검사할 때 최종 화면의 RGB만 보면 되나요?

충분하지 않습니다. 최종 출력은 이미 색역 매핑과 클램프를 거쳤을 수 있습니다. 톤 매핑 전의 선형 RGB 또는 XYZ 변환 결과를 검사하고 최종 출력에서는 하드 클리핑을 별도로 검사해야 합니다.

정리

HDR 아트 QA의 목표는 밝은 픽셀을 무조건 제거하는 것이 아니라 의도되지 않은 색상 손실과 시각적 피로를 자동으로 찾아내는 것입니다. ST 2084 PQ를 니트로 복원하고 톤 매핑 전후의 RGB를 분리해 측정하며 영역·머티리얼·프레임 지속성 정보를 함께 사용하면 HDR 검수를 재현 가능한 CI 파이프라인으로 만들 수 있습니다.