베이크드 AO와 실시간 조명 중첩으로 생기는 이중 음영 자동 탐지 가이드

베이크드 AO 텍스처와 실시간 AO·그림자가 같은 머티리얼에 중첩되면 접촉부가 비정상적으로 검게 보입니다. Unity URP·HDRP와 HLSL 기반의 자동 검사 지표, 디버그 셰이더, 에셋 스캔 절차로 이중 음영을 빠르게 찾고 수정하는 방법을 정리합니다.

✓ 복사 완료!
챕터자동화 테스트 & 회귀 검증
난이도중급
상태● 검토 완료
대상 엔진
Engine Agnostic
최종 업데이트
베이크드 AO와 실시간 조명 중첩으로 생기는 이중 음영 자동 탐지 가이드

핵심 요약

베이크드 AO와 실시간 AO 또는 실시간 그림자는 모두 표면의 간접광과 접촉부를 어둡게 만듭니다. 두 값이 곱해지면 같은 영역이 중복 감쇠되어 비정상적으로 검게 보이는 이중 음영이 발생합니다.

자동 검사는 머티리얼 에셋만 분석해서 끝낼 수 없습니다. AO 텍스처와 패킹 채널은 정적 스캔으로 확인하고 베이크 전용·실시간 전용 렌더 캡처를 비교해 최종 음영의 중첩 정도를 측정해야 합니다.

왜 베이크드 AO와 실시간 조명이 겹치면 이중 음영이 생기는가?

AO는 표면의 틈이나 접촉부에서 주변광이 차단되는 정도를 근사하는 효과입니다. 이 글의 검사 예시에서는 AO 마스크를 0에서 1 사이의 감쇠 계수로 정규화하고, 1은 감쇠 없음, 0은 완전한 차단으로 해석합니다. Unity도 AO가 주름·구멍·가까운 표면에서 주변광을 가려 어둡게 보이도록 하며, 베이크 AO를 라이트맵에 구울 수 있다고 설명합니다. (Unity 매뉴얼)

베이크드 AO 계수를 A_baked, 실시간 AO 또는 실시간 접촉 그림자 계수를 A_runtime이라고 하면 최종 AO는 다음처럼 계산되는 경우가 많습니다.

Atotal=Abaked×AruntimeA_total = A_baked × A_runtime

예를 들어 베이크드 AO가 0.55이고 실시간 AO가 0.6이면 최종 계수는 0.33입니다. 원래 의도한 접촉부의 밝기가 55% 또는 60% 수준이어야 했는데 두 감쇠가 곱해져 33%까지 떨어지는 것입니다.

문제는 AO 값 자체보다 두 소스가 같은 공간 영역에 동시에 강하게 적용된다는 점입니다. 다음 상황에서 특히 잘 나타납니다.

중첩 조합흔한 결과우선 확인할 항목
라이트맵 AO + Screen Space AO벽과 바닥 접촉부가 지나치게 검음베이크 설정의 AO 기여도, SSAO 강도
AO 텍스처 + 실시간 접촉 그림자캐릭터 발밑과 소품 틈이 뭉개짐오클루전 맵 채널, 그림자 거리
버텍스 컬러 AO + 실시간 AO특정 메시의 모서리만 과도하게 어두움버텍스 컬러 사용 규칙, 메시 임포트 옵션
머티리얼 AO + 라이트 프로브 간접광 감쇠이동 오브젝트의 틈이 고정된 것처럼 보임프로브 샘플링과 AO 적용 위치

베이크드 AO와 실시간 AO가 같은 접촉 영역을 어둡게 만드는 비교 이미지

머티리얼만 검사해서 이중 음영을 찾을 수 있는가?

완전히 찾을 수는 없습니다. 머티리얼은 AO 텍스처나 셰이더 프로퍼티를 보유하지만 실시간 AO와 그림자는 카메라, 라이트, 렌더러 기능, 포스트 프로세싱 상태에 따라 달라집니다.

따라서 검사 시스템은 다음 두 계층으로 나누는 것이 안전합니다.

검사 계층확인 대상적합한 방식
정적 에셋 검사오클루전 맵, 버텍스 컬러, 셰이더 키워드, AO 강도AssetDatabase 기반 에디터 스캔
런타임 렌더 검사실제 베이크드 AO와 실시간 AO의 밝기 변화제어된 씬에서 디버그 패스 캡처
상관관계 검사두 AO가 같은 픽셀 영역을 어둡게 하는지마스크 비교와 공간 상관계수 계산
수정 검사수정 후 음영이 정상 범위로 돌아왔는지동일 조명 조건의 회귀 캡처

정적 검사는 위험 후보를 빠르게 줄이는 역할을 합니다. 최종 판정은 동일한 머티리얼과 동일한 카메라를 사용한 두 번의 렌더 캡처로 수행해야 합니다.

자동 머티리얼 검사는 어떤 값을 비교해야 하는가?

핵심은 알베도와 조명 조건을 고정한 뒤 AO 소스만 분리하는 것입니다. 다음 세 가지 출력을 준비하면 대부분의 이중 음영을 수치화할 수 있습니다.

  1. 베이크드 AO만 적용한 캡처
  2. 실시간 AO 또는 실시간 그림자만 적용한 캡처
  3. 두 소스를 모두 적용한 최종 캡처

각 캡처를 선형 색 공간의 휘도 값으로 변환합니다. 단순히 sRGB 픽셀 값을 비교하면 어두운 영역의 차이가 왜곡될 수 있으므로 선형 색 공간에서 비교하는 것이 좋습니다.

두 감쇠를 곱한 결과는 최종 AO 계수입니다. 이 값만으로 이중 음영 여부를 판정하지 않고, 두 소스의 공간적 중첩과 함께 봅니다.

Atotal=Abaked×AruntimeA_total = A_baked × A_runtime

여기에 두 어두운 영역이 실제로 겹치는 정도를 나타내는 상관계수 C를 곱하면 검사 점수를 만들 수 있습니다.

S=clamp((1−Abaked)×(1−Aruntime)×C,0,1)S = clamp((1 - A_baked) × (1 - A_runtime) × C, 0, 1)

S가 높을수록 두 AO 소스가 같은 위치에서 강하게 작동한다는 의미입니다. 시작 기준으로 A_baked < 0.65, A_runtime < 0.85, C > 0.55를 사용할 수 있지만 프로젝트의 톤 매핑과 아트 스타일에 맞춰 보정해야 합니다. 이 수치는 엔진의 공통 규칙이 아니라 초기 탐색용 기준입니다.

공간 상관계수는 어떻게 계산할까?

AO 마스크를 일정한 해상도로 다운샘플링한 뒤 어두운 픽셀을 이진 마스크로 변환합니다. 두 마스크가 모두 어두운 픽셀의 비율을 전체 후보 영역으로 나누면 간단한 중첩률을 얻을 수 있습니다.

C=overlap(Mbaked,Mruntime)/union(Mbaked,Mruntime)C = overlap(M_baked, M_runtime) / union(M_baked, M_runtime)

이 방식은 복잡한 통계 계산 없이도 보고서에 설명하기 쉽습니다. 다만 작은 구멍이나 얇은 메시에서는 안티앨리어싱의 영향을 받으므로 3×3 또는 5×5 커널로 마스크를 평균화한 후 비교하는 편이 안정적입니다.

Unity URP와 HDRP에서 검사 패스를 어떻게 구현할까?

Unity URP와 HDRP 모두 프로젝트 설정과 렌더 경로에 따라 실시간 AO가 적용되는 위치가 달라질 수 있습니다. 따라서 머티리얼 셰이더가 엔진 내부의 AO 텍스처를 직접 추측하기보다 커스텀 디버그 패스가 계산한 값을 명시적으로 전달하도록 설계하는 것이 좋습니다.

예를 들어 HLSL 기반 디버그 셰이더에서는 다음처럼 베이크드 AO, 실시간 AO, 최종 중첩 점수를 각각 출력할 수 있습니다.

float bakedAo = SAMPLE_TEXTURE2D(_BakedAO, sampler_BakedAO, input.uv).r;
float runtimeAo = input.runtimeAo;
float totalAo = bakedAo * runtimeAo;
float doubleShadeScore = saturate((1.0 - bakedAo) * (1.0 - runtimeAo));

return float4(bakedAo, runtimeAo, totalAo, doubleShadeScore);

이 예제에서 input.runtimeAo는 URP의 Screen Space Ambient Occlusion, HDRP의 화면 공간 오클루전 또는 별도의 그림자 분석 패스가 제공하는 값을 의미합니다. 실제 셰이더에 그대로 붙이는 내장 변수명이 아니라 프로젝트의 렌더 파이프라인에서 생성한 디버그 입력으로 취급해야 합니다.

셰이더의 doubleShadeScore는 한 픽셀에서 두 마스크가 함께 어두운 정도를 나타내는 로컬 값입니다. 프레임 전체의 최종 점수는 이 마스크들의 중첩률을 별도로 계산해 C# 판정식에 전달합니다.

색상 채널은 다음 규칙으로 해석하면 됩니다.

  • 빨간색: 베이크드 AO
  • 초록색: 실시간 AO 또는 실시간 그림자
  • 파란색: 두 값을 곱한 최종 AO
  • 알파: 이중 음영 위험도

알파 채널이 높은 픽셀이 넓은 면적에 지속적으로 나타난다면 소스 중 하나의 영향도를 줄이거나 제거할 후보입니다.

AO 소스별 채널과 이중 음영 위험도를 표시하는 디버그 셰이더 결과

정적 에셋 스캔은 어떻게 구성할까?

에디터 단계에서는 머티리얼의 셰이더와 프로퍼티를 검색해 AO 입력을 목록화합니다. 단, 프로퍼티 이름만으로 AO를 확정하면 안 됩니다. _OcclusionMap이 실제로 사용되지 않을 수 있고 AO가 텍스처의 G 채널이나 버텍스 컬러에 패킹되어 있을 수도 있기 때문입니다.

최소한 다음 정보를 보고서에 기록합니다.

필드의미
MaterialPath머티리얼 에셋 경로
ShaderName사용 중인 ShaderLab 셰이더 이름
OcclusionProperty오클루전 맵 프로퍼티 이름
OcclusionChannelR, G, B, A 중 사용 채널
OcclusionStrength머티리얼 AO 강도
VertexColorAO버텍스 컬러 AO 사용 여부
RendererLightmap해당 렌더러의 라이트맵 사용 여부
RuntimeAOProfile실시간 AO가 적용되는 렌더 프로파일

검사 결과를 C# 에디터 도구에서 다루기 위한 단순한 데이터 구조는 다음과 같습니다.

public sealed class MaterialScanResult
{
    public string MaterialPath;
    public string ShaderName;
    public bool HasBakedAoInput;
    public bool HasRuntimeAoCandidate;
    public float BakedAoMean;
    public float RuntimeAoMean;
    public float Overlap;
    public float Score;
    public bool Suspect;
}

public static MaterialScanResult Evaluate(
    string materialPath,
    string shaderName,
    bool hasBakedAoInput,
    bool hasRuntimeAoCandidate,
    float bakedAoMean,
    float runtimeAoMean,
    float overlap)
{
    float score = UnityEngine.Mathf.Clamp01(
        (1f - bakedAoMean) * (1f - runtimeAoMean) * overlap);

    return new MaterialScanResult
    {
        MaterialPath = materialPath,
        ShaderName = shaderName,
        HasBakedAoInput = hasBakedAoInput,
        HasRuntimeAoCandidate = hasRuntimeAoCandidate,
        BakedAoMean = bakedAoMean,
        RuntimeAoMean = runtimeAoMean,
        Overlap = overlap,
        Score = score,
        Suspect = hasBakedAoInput && hasRuntimeAoCandidate && score >= 0.35f
    };
}

이 코드는 실제 텍스처를 읽고 렌더 캡처를 만드는 부분을 생략한 판정 계층입니다. bakedAoMean과 runtimeAoMean은 선형화된 AO 마스크 평균값이어야 하며 overlap은 동일한 메시 또는 동일한 화면 영역에서 계산해야 합니다.

이중 음영을 어떻게 자동 판정하고 수정할까?

다음 순서로 검사 파이프라인을 구성하면 아티스트가 보고서를 바로 확인할 수 있습니다.

1단계: AO 입력 소스를 인벤토리화한다

ShaderLab 셰이더의 오클루전 맵 프로퍼티, AO 강도, 버텍스 컬러 사용 여부를 검색합니다. 메시 렌더러의 라이트맵 정적 여부와 라이트맵 UV2 존재 여부도 함께 기록합니다.

AO 맵이 없더라도 라이트맵에 AO가 구워졌을 수 있으므로 머티리얼 검사 결과만으로 정상 판정을 내리지 않습니다.

2단계: 제어된 씬에서 소스를 분리해 캡처한다

테스트 씬에는 중립적인 회색 알베도, 고정 카메라, 고정 노출, 동일한 방향성 라이트를 사용합니다. 다음 설정을 번갈아 적용합니다.

  • 베이크드 AO만 켜기
  • 실시간 AO와 접촉 그림자만 켜기
  • 두 소스 모두 켜기

캡처 사이에는 톤 매핑, 자동 노출, 블룸처럼 결과 밝기에 영향을 주는 후처리를 끄거나 동일하게 고정해야 합니다.

3단계: 마스크와 휘도를 비교한다

세 캡처를 선형 색 공간으로 읽고 AO 영향이 큰 영역을 분리합니다. 평균값뿐 아니라 최솟값, 하위 5% 분위수, 연속 영역의 면적을 함께 저장하면 작은 노이즈와 실제 문제를 구분하기 쉽습니다.

권장 보고 항목은 다음과 같습니다.

  • BakedAoMean: 베이크드 AO 평균
  • RuntimeAoMean: 실시간 AO 평균
  • Overlap: 두 마스크의 공간 중첩률
  • FinalLuminanceDrop: 기준 조명 대비 최종 휘도 감소량
  • SuspectAreaRatio: 임계값을 넘은 픽셀 비율

4단계: 자동 수정 후보를 제안한다

검사 도구가 머티리얼을 즉시 변경하기보다는 원인별 수정 후보를 제시하고 아티스트가 승인하도록 만드는 편이 안전합니다.

판정 상황권장 수정
라이트맵에 AO가 충분히 포함됨정적 오브젝트의 실시간 AO 제외 또는 강도 감소
이동 오브젝트라 베이크드 AO를 사용할 수 없음AO 텍스처를 중립값으로 교체하고 실시간 AO 유지
실시간 접촉 그림자만 필요함베이크 단계에서 AO 기여도 제거
AO가 베이스 컬러에 직접 칠해짐베이스 컬러에서 cavity 음영을 분리하고 AO 입력으로 이동
특정 메시의 UV2가 겹침라이트맵 UV 생성 규칙과 패딩 재검토

중립 AO 값은 일반적으로 1입니다. 하지만 텍스처 패킹 규칙과 셰이더의 채널 해석이 프로젝트마다 다르므로 자동 교체 전에 반드시 실제 셰이더 프로퍼티와 채널 설정을 확인해야 합니다.

검사 결과의 오탐을 어떻게 줄일까?

모든 어두운 접촉부가 이중 음영은 아닙니다. 아티스트가 의도적으로 그린 cavity, 금속 표면의 낮은 반사율, 강한 방향성 조명도 비슷한 결과를 만들 수 있습니다.

오탐을 줄이려면 다음 규칙을 추가합니다.

  • AO 텍스처의 평균값만 보지 말고 밝은 영역과 어두운 영역의 공간 분포를 함께 본다.
  • 알베도와 AO의 곱으로 생긴 음영은 검사 대상에서 제외한다.
  • 한두 픽셀 크기의 작은 구멍은 최소 연결 영역 기준으로 제거한다.
  • 스킨드 메시와 이동 오브젝트는 라이트맵 AO 검사에서 별도 프로파일로 분류한다.
  • 카메라와 거리에 따라 실시간 AO가 사라지는 경우를 고려해 여러 거리에서 캡처한다.
  • 머티리얼별 임계값과 프롭, 환경 소품, 캐릭터별 임계값을 분리한다.

특히 베이스 컬러에 이미 구워진 음영은 머티리얼 검사에서 AO 텍스처와 구분하기 어렵습니다. 이 경우 텍스처 분석만으로 확정하지 말고 아트 가이드에 정의된 cavity_allowed 또는 ao_source 메타데이터를 에셋에 추가하는 것이 효과적입니다.

실무용 머티리얼 검사 체크리스트

  • 오클루전 맵의 실제 사용 채널을 기록했는가?
  • AO 강도가 1보다 크게 증폭되고 있지 않은가?
  • 라이트맵 베이크 설정에서 AO 기여도가 활성화되어 있는가?
  • Screen Space AO 또는 HDRP 오클루전이 해당 카메라에서 활성화되어 있는가?
  • 실시간 접촉 그림자가 별도의 감쇠로 다시 곱해지고 있지 않은가?
  • 베이크 전용·실시간 전용·통합 캡처를 모두 비교했는가?
  • 이중 음영 영역의 중첩률과 면적 비율을 기록했는가?
  • 의도된 cavity 아트와 실제 조명 오류를 구분했는가?
  • 수정 후 동일한 조명과 노출로 회귀 검사를 수행했는가?

자주 묻는 질문 (FAQ)

베이크드 AO와 실시간 AO 중 하나를 반드시 꺼야 하나요?

아닙니다. 스타일과 플랫폼에 따라 둘을 약하게 함께 사용할 수 있습니다. 다만 두 감쇠가 같은 영역에서 곱해지는지 측정하고 최종 휘도 감소량을 제한해야 합니다.

머티리얼 에셋만 분석하면 충분한가요?

충분하지 않습니다. 실시간 AO와 그림자는 카메라와 렌더 파이프라인 상태에 의존하므로 제어된 씬의 런타임 캡처가 필요합니다.

AO 텍스처가 없어도 이중 음영이 발생할 수 있나요?

가능합니다. 라이트맵, 버텍스 컬러, 베이스 컬러에 그려진 cavity, 실시간 Screen Space AO가 각각 AO처럼 작동할 수 있습니다. 검사기는 텍스처 검색과 함께 라이트맵 및 셰이더 입력을 확인해야 합니다.

정리

베이크드 AO와 실시간 조명의 이중 음영은 단순한 머티리얼 속성 오류가 아니라 여러 렌더링 단계의 감쇠가 중복되는 문제입니다. 가장 안정적인 해결책은 AO 입력을 인벤토리화한 뒤 제어된 렌더 캡처에서 베이크드 소스와 실시간 소스를 분리하고 A_total, 중첩률, 의심 영역 비율을 함께 평가하는 것입니다.

Unity URP와 HDRP 프로젝트에서는 HLSL 디버그 패스와 C# 에디터 스캔을 결합하면 아티스트가 결과를 색상과 수치로 동시에 확인할 수 있습니다. 최종적으로는 프로젝트의 조명 스타일에 맞춰 AO 소스의 책임을 하나로 정하고 자동 검사 결과를 회귀 테스트에 포함하는 것이 좋습니다.