book/38-tech-multicolor-outline-and-line-width.md

N/A

38. 기술 심화(실전): Multi-Color Outline + Line Width

다색 외곽선과 거리 기반 선폭 조절을 URP로 구현하는 실전 패턴

38. 기술 심화(실전): Multi-Color Outline + Line Width

[B] 외곽선(outline)은 서브컬쳐 룩에서 “마지막 장식”이 아니라, 캐릭터를 읽게 만드는 가독성 인프라입니다. 특히 네온/복잡 배경에서는 diffuse/ramp만으로 실루엣을 유지하기 어려워, 라인이 룩의 뼈대가 됩니다.

  • [B] 목표: 부위/재질별로 다른 선색을 안정적으로 분기하고(T006), 카메라 거리/FOV/해상도 변화에서도 두께가 튀지 않게 한다(T007).
  • [A/B] 주의: HDR 장면에서는 라인이 톤매핑/블룸과 강하게 상호작용하므로, “어디에서 그리나(패스 위치)”가 결과를 좌우한다.

목적

  • [B] 마스크 기반 다색 외곽선을 구현한다.
  • [A/B] 거리/해상도 변화에서도 선폭 일관성을 유지한다.

증거 등급 요약(A/B/C)

  • [B] ZZZ 계열 역분석에서 다색 분기 반복
  • [A/B] HDR 장면에서 선색/선폭 제어 중요

핵심 개념

서론: 라인은 ‘실루엣’이면서 ‘식별 신호’다

  • [B] 외곽선은 실루엣(geometry 경계) 정보로 캐릭터를 읽게 만들고, 다색 분기는 “부위/재질군”을 즉시 식별시키는 신호로 동작한다.
  • [B] 즉, outline은 shading과 독립된 UI 레이어처럼 취급해야 일관성이 높다(그리기 순서/톤/HDR/temporal의 영향을 크게 받음).

개론: 구현 경로(2가지)와 역할 분담

  • [B] Inverted hull(버텍스 extrude): 메쉬 경계를 기반으로 안정적이며, 캐릭터에 붙는 라인에 유리하다.
  • [B] Screen-space edge(depth/normal): 배경과의 경계 보강에 강하지만, 내부 디테일까지 라인으로 잡힐 수 있어 bias/scale 튜닝이 필요하다.
  • [B] 실전에서는 “캐릭터 라인 = hull”, “추가 보강 = depth edge(T008)”처럼 역할을 분리하면 회귀가 줄어든다.

이론: 선폭을 ‘픽셀 단위’로 고정하려면(거리/FOV/해상도)

  • [B] 선폭을 월드 단위로만 밀면, 카메라가 멀어질수록 얇아져 사라진다.
  • [B] 반대로 NDC(스크린) 단위로만 밀면, FOV/해상도에서 튐이 생긴다.
  • [B] 가장 흔한 근사는 “픽셀 두께 -> NDC 오프셋 -> clipPos.w로 보정”이다.
HLSL
// Inverted hull 스타일의 개념 스니펫(버텍스 단계)
float2 dir = normalize(normalVS.xy);                 // 화면에서 밀 방향
float  offsetNdc = (_OutlineWidthPx * 2.0) / _ScreenParams.y;
clipPos.xy += dir * offsetNdc * clipPos.w;           // 원근 보정

심화: HDR/temporal에서 라인이 무너지는 지점

  • [A/B] HDR 씬에서 라인을 post 이후에 그리면 톤매핑/블룸과 분리되어 색이 뜨거나 클리핑되기 쉽다.
  • [B] 반대로 post 이전에 그리면 톤매핑의 영향을 받아 “씬과 같은 룩”으로 정합되지만, 라인이 bloom에 과하게 먹을 수 있어 clamp/soft-knee가 필요하다.
  • [B] TAA 환경에서는 라인이 얇을수록 히스토리 오염에 취약하므로(43장), 선폭/색 분기만으로 해결하려 하지 말고 temporal 안정화와 함께 튜닝한다.

코드 해설: 다색 분기(단일 채널 압축)

  • [B] split 임계값 체인은 단일 마스크 채널에서 다중 라인 색을 복원하는 압축 규칙이다.
  • [B] 핵심은 “임계값 목록 자체가 아트 계약”이므로, 페인팅 변경 시에도 동일 규칙을 유지해야 한다.
HLSL
half4 tMask = SAMPLE_TEXTURE2D(_OutlineMask, sampler_OutlineMask, i.uv);
bool4 split = tMask.r < half4(0.8, 0.6, 0.4, 0.2);
half3 line = split.x ? _Line1.rgb : _Line0.rgb;
line = split.y ? _Line2.rgb : line;
line = split.z ? _Line3.rgb : line;
line = split.w ? _Line4.rgb : line;
C#
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public sealed class OutlineFeature : ScriptableRendererFeature
{
    [SerializeField] private Material outlineMaterial;
    private OutlinePass _pass;

    public override void Create()
    {
        _pass = new OutlinePass(outlineMaterial)
        {
            renderPassEvent = RenderPassEvent.AfterRenderingOpaques
        };
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (outlineMaterial == null) return;
        renderer.EnqueuePass(_pass);
    }

    private sealed class OutlinePass : ScriptableRenderPass
    {
        private readonly Material _mat;
        public OutlinePass(Material mat) => _mat = mat;
        public override void Execute(ScriptableRenderContext context, ref RenderingData data)
        {
            var draw = CreateDrawingSettings(new ShaderTagId("UniversalForward"), ref data, data.cameraData.defaultOpaqueSortFlags);
            draw.overrideMaterial = _mat;
            var filter = new FilteringSettings(RenderQueueRange.opaque);
            context.DrawRenderers(data.cullResults, ref draw, ref filter);
        }
    }
}

디버깅 포인트

  • [B] 마스크 임계값 구간별로 false color 뷰를 만들어 분기 경계를 눈으로 확인한다.
  • [B] 카메라 줌/FOV 변경 시 line width 함수가 단조 증가/감소를 유지하는지 그래프로 점검한다.
  • [A/B] HDR 장면에서 라인 색이 tone mapping 이후 clipping 되는지 Waveform/Histogram로 확인한다.

URP 매핑 포인트

설계 해석

  • [B] outline pass는 opaque 이후에 배치하고, 투명 간섭이 심하면 depth prepass를 추가한다.

  • [A/B] 선폭 함수는 거리와 FOV를 동시에 입력으로 받아야 렌즈 변경 시 두께 일관성을 유지한다.

  • [B] base pass + outline pass 분리

  • [B] 라인 폭 함수는 거리/FOV와 함께 튜닝

  • [A/B] HDR 프로젝트는 “라인을 언제 톤매핑할지”를 먼저 결정한다.

  • [B] 권장 기본값: AfterRenderingOpaques(post 이전)에서 라인을 그려 톤매핑과 함께 정합시키고, 라인 하이라이트는 clamp로 제어한다.

실패 패턴/오해

  • [B] 임계값 고정으로 페인팅 변경 시 색 분기 붕괴
  • [B] 선폭 함수 설정 오류로 줌 시 깜빡임
  • [A/B] HDR 씬에서 라인을 post 이후에 그려 색이 ‘뜸’ 또는 클리핑(톤/HDR 정합 실패)

실무 체크리스트

Sources (섹션 단위 인용)