book/24-debugging-playbook-unity6-urp.md

N/A

24. Debugging Playbook (Unity 6 / URP)

Unity 6.3(6000.3) / URP 17.3.0에서 Frame Debugger/RenderGraph Viewer 기반으로 “증상→원인→확인→해결” 루틴을 정리한 실전 플레이북

24. Debugging Playbook (Unity 6 / URP 17.3.0)

이 챕터는 “이상하다”를 “재현 가능하고, 추적 가능하고, 수정 가능한” 상태로 바꾸기 위한 실전 디버깅 루틴 모음입니다.

핵심 철학:

  • Pass 계약부터 확인한다(내 오브젝트가 어떤 LightMode Pass로 그려지는지).
  • 그 다음 데이터 흐름을 확인한다(SurfaceData/InputData, Light 루프).
  • 마지막에 키워드/Variant를 확인한다(Forward+/Decal/Rendering Layers 등).

24.0 디버깅 도구 체크리스트(권장)

  • Frame Debugger: “어떤 ShaderLab Pass가 실제로 사용됐나?”를 가장 빠르게 확인
  • RenderGraph Viewer: Depth/Normals/History/MotionVector 같은 리소스가 언제 생성/소비되는지 확인
  • URP Debug Display(가능하면): 라이팅/GI/그림자 경로 확인
  • RenderDoc(필요 시): 실제 RT/DSV 출력 검증

24.1 30초 트리아주: “Pass 계약이 깨졌나?”부터 본다

  1. Frame Debugger에서 문제 오브젝트 drawcall을 선택한다
  2. 아래 중 무엇이 보이는지 확인한다
  • UniversalForward(ForwardLit)
  • UniversalGBuffer(GBuffer)
  • DepthOnly
  • DepthNormals
  • MotionVectors
  • ShadowCaster

기대한 LightMode가 없다면, 대부분 원인은 ShaderLab Pass 누락/태그 오류입니다.

계약표: book/20-urp-pass-tags-and-lightmode-contract.md

24.2 자주 터지는 문제 Top 10: “증상→원인→확인→해결”

24.2.1 Forward+에서 추가 라이트가 0개처럼 보임

증상:

  • Forward+ ON에서 추가 라이트가 적용되지 않음(또는 특정 머티리얼만)

핵심 원인:

  • Forward+에서 GetAdditionalLightsCount()가 0을 반환할 수 있음(계약)

확인:

해결:

  • 추가 라이트 루프를 직접 구현했다면 LIGHT_LOOP_BEGIN/END로 전환
  • 셰이더에 _CLUSTER_LIGHT_LOOP variant가 존재하는지 확인

관련 챕터:

24.2.2 Deferred에서 머티리얼이 이상하게 보임(빛이 안 먹거나, fallback)

증상:

  • Deferred 렌더러에서 특정 머티리얼이 어둡거나 이상하게 렌더됨

핵심 원인:

  • UniversalGBuffer pass가 없어서 Deferred 경로에서 fallback 또는 forward-only로 빠짐

확인:

  • Frame Debugger에서 opaque가 GBuffer로 그려지는지 확인
  • URP 주석(계약): <URP>/Runtime/UniversalRenderer.cs:388

해결:

  • UniversalGBuffer pass 추가(또는 URP Lit GBuffer pass를 기반으로 구현)
  • Deferred 불가 머티리얼이면 UniversalForwardOnly 전략을 고려(특수 셰이더)

관련:

24.2.3 SSAO/Outline이 깨짐(노말이 이상하거나 텍스처가 비어 있음)

증상:

  • SSAO가 전혀 먹지 않거나, Outline이 깜빡이거나, 노말 방향이 뒤집힘

핵심 원인:

  • DepthNormals pass가 없거나, 계약(공간/인코딩)이 URP 구현과 다름

확인:

  • Frame Debugger에서 DepthNormals pass가 호출되는지 확인
  • RenderGraph Viewer에서 DepthNormalsTexture 생성/소비 확인
  • URP 소비 태그: <URP>/Runtime/Passes/DepthNormalOnlyPass.cs:19

해결:

  • DepthNormals pass 제공(URP LitDepthNormalsPass 기반 권장)
  • custom DepthNormals 구현 시: normalWS/normalVS/인코딩 방식이 URP와 일치하는지 확인

관련:

24.2.4 TAA/모션블러/리프로젝션이 이상함(고스팅/번짐/흔들림)

증상:

  • 고스팅이 심하거나, 움직일 때 잔상이 남음

핵심 원인:

  • MotionVectors pass 누락 또는 잘못된 velocity 출력

확인:

  • URP 소비 태그: <URP>/Runtime/Passes/MotionVectorRenderPass.cs:14 (MotionVectors)
  • Frame Debugger에서 MotionVectors pass가 호출되는지 확인

해결:

  • MotionVectors pass 추가
  • Lit.shader처럼 ObjectMotionVectors.hlsl#include_with_pragmas로 포함(pragma 누락 방지)

관련:

24.2.5 그림자가 안 생기거나(특정 재질만) 컷아웃 그림자가 깨짐

증상:

  • 어떤 오브젝트는 그림자가 아예 없음
  • 컷아웃(AlphaTest) 오브젝트의 그림자가 구멍이 안 뚫림/과도하게 뚫림

핵심 원인:

  • ShadowCaster pass 누락
  • ShadowCaster에서 _ALPHATEST_ON 처리/컷오프 값이 ForwardLit과 불일치

확인:

  • Frame Debugger/ShadowMap 렌더 단계에서 해당 오브젝트가 그려지는지 확인
  • 셰이더에 LightMode=ShadowCaster pass가 있는지 확인

해결:

  • ShadowCaster pass 추가(URP ShadowCasterPass 기반 권장)
  • AlphaTest 머티리얼 프로퍼티/CBUFFER가 모든 pass에서 동일한지 확인(SRP Batcher 포함)

관련:

24.2.6 SRP Batcher가 꺼져 성능이 급락

증상:

  • SRP Batcher가 동작하지 않는 것 같고, CPU 비용이 증가

핵심 원인:

  • CBUFFER_START(UnityPerMaterial) 레이아웃이 pass마다 다르거나 #if로 변형됨

확인:

  • pass 간 CBUFFER 내용/순서가 동일한지 확인

해결:

  • 머티리얼 프로퍼티를 UnityPerMaterial에 고정하고, 조건부 컴파일로 구조가 바뀌지 않게 함

관련:

24.2.7 Decal(DBuffer)이 특정 재질에서만 안 먹음

증상:

  • 프로젝트에서 Decal은 켜져 있는데 특정 셰이더만 데칼이 적용되지 않음

핵심 원인:

  • ApplyDecalToSurfaceData(...) 호출 경로가 없거나, _DBUFFER variant가 없음

확인:

  • LitForwardPass 흐름에서 decal 적용 지점 확인: <URP>/Shaders/LitForwardPass.hlsl 주변
  • 함수 정의: <URP>/ShaderLibrary/DBuffer.hlsl:191

해결:

  • URP Lit callflow를 유지하고, decal 적용 지점을 보존

관련:

24.2.8 Rendering Layers가 깨짐(조명 레이어가 안 맞음)

증상:

  • Light Layers/Rendering Layers 설정이 있어도, 특정 머티리얼만 레이어가 무시됨

핵심 원인:

  • ForwardLit 엔트리가 SV_Target1(렌더링 레이어 출력) 계약을 따르지 않음

확인:

  • LitPassFragment 정의: <URP>/Shaders/LitForwardPass.hlsl:223 (_WRITE_RENDERING_LAYERS)

해결:

  • URP Lit과 동일하게 out SV_Target1 출력 계약 유지

관련:

24.2.9 DepthTexture는 있는데 SceneDepth 샘플이 항상 1(또는 0)처럼 나옴

증상:

  • SampleSceneDepth 결과가 기대와 다름

핵심 원인:

  • DepthTexture 생성 단계가 실제로 켜져 있지 않음
  • UV/렌더스케일/XR에서 올바르게 샘플링하지 않음
  • raw depth를 선형화하지 않음

확인:

  • RenderGraph Viewer에서 DepthTexture 생성 확인
  • LinearEyeDepth(raw, _ZBufferParams) 적용 여부 확인

해결:

  • “생성→선언→샘플링→선형화” 4단계를 체크리스트로 점검

관련:

24.2.10 XR에서 모션 벡터/리프로젝션이 깨짐

증상:

  • XR에서만 모션 벡터 관련 기능이 이상함

핵심 원인:

  • XR 전용 모션 벡터 계약(XRMotionVectors) 미제공 또는 스텐실 계약 누락

확인:

  • Lit.shaderXRMotionVectors pass 존재 여부 확인
  • Frame Debugger에서 XR 경로 pass 소비 확인

해결:

  • URP Lit의 XR MotionVectors pass 구조를 기반으로 구현(Stencil/define 포함)

관련:

24.3 검색 레시피(원인 좁히기)

Generated를 먼저 보는 게 가장 빠릅니다.

  1. Pass/Include: book/generated/urp-lit-map.md
  2. 심볼 정의/xref: book/generated/urp-17.3.0/xref/lit-key-symbols.md
  3. 함수/구조체 인덱스: book/generated/urp-17.3.0/symbols/*

소스에서 직접 찾기(rg 예시):

POWERSHELL
rg -n \"GetAdditionalLightsCount\\(\" Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl
rg -n \"LIGHT_LOOP_BEGIN\" Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl
rg -n \"k_MotionVectorsLightModeTag\" Packages/com.unity.render-pipelines.universal/Runtime/Passes/MotionVectorRenderPass.cs
rg -n \"new ShaderTagId\\(\\\"DepthOnly\\\"\\)\" Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthOnlyPass.cs

24.4 RenderGraph Pass Culling 30초 점검 루틴

RenderGraph에서 "아무 에러 없이 효과가 사라지는" 경우는 패스 culling일 가능성이 높습니다.

  1. RenderGraph Viewer에서 해당 패스가 그래프에 존재하는지 확인
  2. 패스 출력 핸들이 다음 패스 입력으로 연결되는지 확인
  3. 카메라 컬러 교체 패턴이면 교체본이 후속 패스에서 소비되는지 확인
  4. 전역 바인딩만 있고 소비 경로가 없으면 임시 소비 패스를 붙여 생존성 확인

샘플 참고:

  • samples/Unity6_Rendering_Bible/04_Render_Graph_System/03_RecordRenderGraph_Migration_Checklist.md
  • samples/Unity6_Rendering_Bible/04_Render_Graph_System/04_RenderGraph_Debugging_and_Culling.md