book/42-tech-depth-rim-and-screen-space-edge.md

N/A

42. 기술: Depth Rim + Screen-Space Edge

깊이/노멀 기반 림과 스크린 엣지를 결합해 캐릭터 실루엣 가독성을 높이는 패턴

42. 기술: Depth Rim + Screen-Space Edge

[B] rim/edge는 “외곽선”만으로 해결하기 어려운 장면(밝은 배경, 얇은 소품, 복잡한 실루엣)에서 캐릭터를 읽게 만드는 보강 신호입니다. 핵심은 라인을 더 세게 그리는 게 아니라, 저주파(rim)와 고주파(edge)를 분리해 역할을 나누는 것입니다.

목적

  • [B] 배경 대비 캐릭터 실루엣을 안정적으로 분리한다.
  • [A/B] URP DepthNormals 계약 위에서 재현 가능한 edge/rim 결합식을 제시한다.

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

  • [A] 플랫폼 발표에서 캐릭터 가독성과 고대비 장면 대응의 중요성이 반복된다.
  • [B] Zhihu/CSDN 역분석에서 depth rim + line 보강 조합이 반복된다.
  • [C] 내부 샘플 반경/커널 구성은 프로젝트별로 상이하다.

핵심 개념

이론 배경

  • [B] rim은 법선-시선 관계의 저주파 신호, edge는 depth 기울기의 고주파 신호라 서로 보완적으로 동작한다.
  • [B] 두 신호를 분리하면 내부 디테일 과강조를 피하면서 외곽 가독성만 강화할 수 있다.
  • [C] 커널 반경을 키우면 안정성은 늘지만 라인 지연/번짐이 증가하므로 플랫폼별 한계를 정의해야 한다.

핵심은 "림은 밝기 보정, 엣지는 윤곽 보정"으로 역할을 분리하는 것이다. [B]

HLSL
float LinearEye(float rawDepth)
{
    return LinearEyeDepth(rawDepth, _ZBufferParams);
}

float EvalDepthEdge(float2 uv, float2 px)
{
    float dC = LinearEye(SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r);
    float dR = LinearEye(SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, uv + float2(px.x, 0)).r);
    float dU = LinearEye(SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, uv + float2(0, px.y)).r);
    float grad = abs(dR - dC) + abs(dU - dC);
    return saturate((grad - _EdgeBias) * _EdgeScale);
}

float EvalDepthRim(float3 nWS, float3 vWS, float2 uv)
{
    float fres = pow(1.0 - saturate(dot(normalize(nWS), normalize(vWS))), _RimPower);
    float edge = EvalDepthEdge(uv, _ScreenParams.zw); // 1/width, 1/height
    return saturate(fres * _RimIntensity + edge * _EdgeRimBlend);
}
  • [B] line-only 접근은 밝은 배경에서 경계가 사라지므로 rim 가중치를 병행한다.
  • [B] edge-only 접근은 내부 음영이 과분리되므로 bias/scale을 거리 기반으로 보정한다.

결론: rim과 edge를 “같은 문제”로 취급하지 않는다

  • [B] rim은 캐릭터 표면 방향성(법선-시선) 신호라, 캐릭터 내부 스타일과 어울리는 “광량 보정”에 가깝다.
  • [B] edge는 배경과의 분리 신호라, 카메라 거리/배경 복잡도에 따라 가중치를 조절해야 한다.
  • [B] 따라서 T006(hull outline)과 함께 쓸 때도 역할을 섞지 말고, “캐릭터 라인”과 “배경 분리 보강”을 분리해 튜닝한다.

URP 매핑 포인트

설계 해석

  • [B] 근접샷은 rim 비중, 원경 군중샷은 edge 비중을 높이는 거리 기반 블렌딩이 안정적이다.

  • [A/B] DepthNormals 비용이 큰 플랫폼은 캐릭터 전용 레이어로 적용 범위를 축소한다.

  • [A/B] 입력 계약: DepthNormals 사용 시 DepthNormals pass 누락을 금지한다.

  • [B] 적용 위치:

    • 캐릭터 셰이더 내부 rim 계산(UniversalForward)
    • 후처리 edge pass(RendererFeature)에서 최종 line 보강
  • [B] 카메라 거리별 line 폭:

    • _EdgeScale = lerp(_NearScale, _FarScale, saturate(viewDepth * _DepthFade))

실패 패턴/오해

  • [B] _ZBufferParams/역 Z 설정을 고려하지 않아 edge가 반전된다.
  • [B] MSAA resolve 전 depth를 샘플해 깜빡임이 발생한다.
  • [C] 노멀맵 세부 패턴까지 edge로 취급해 "모공 라인화"가 생긴다.

실무 체크리스트

  • DepthNormals/MotionVectors

Sources (섹션 단위 인용)

원리/패턴

엔진/플랫폼 맥락