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 계약이 깨졌나?”부터 본다
- Frame Debugger에서 문제 오브젝트 drawcall을 선택한다
- 아래 중 무엇이 보이는지 확인한다
UniversalForward(ForwardLit)UniversalGBuffer(GBuffer)DepthOnlyDepthNormalsMotionVectorsShadowCaster
기대한 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을 반환할 수 있음(계약)
확인:
- 정의 확인:
<URP>/ShaderLibrary/RealtimeLights.hlsl:271 - generated xref:
book/generated/urp-17.3.0/xref/lit-key-symbols.md
해결:
- 추가 라이트 루프를 직접 구현했다면
LIGHT_LOOP_BEGIN/END로 전환 - 셰이더에
_CLUSTER_LIGHT_LOOPvariant가 존재하는지 확인
관련 챕터:
24.2.2 Deferred에서 머티리얼이 이상하게 보임(빛이 안 먹거나, fallback)
증상:
- Deferred 렌더러에서 특정 머티리얼이 어둡거나 이상하게 렌더됨
핵심 원인:
UniversalGBufferpass가 없어서 Deferred 경로에서 fallback 또는 forward-only로 빠짐
확인:
- Frame Debugger에서 opaque가
GBuffer로 그려지는지 확인 - URP 주석(계약):
<URP>/Runtime/UniversalRenderer.cs:388
해결:
UniversalGBufferpass 추가(또는 URP Lit GBuffer pass를 기반으로 구현)- Deferred 불가 머티리얼이면
UniversalForwardOnly전략을 고려(특수 셰이더)
관련:
24.2.3 SSAO/Outline이 깨짐(노말이 이상하거나 텍스처가 비어 있음)
증상:
- SSAO가 전혀 먹지 않거나, Outline이 깜빡이거나, 노말 방향이 뒤집힘
핵심 원인:
DepthNormalspass가 없거나, 계약(공간/인코딩)이 URP 구현과 다름
확인:
- Frame Debugger에서
DepthNormalspass가 호출되는지 확인 - RenderGraph Viewer에서 DepthNormalsTexture 생성/소비 확인
- URP 소비 태그:
<URP>/Runtime/Passes/DepthNormalOnlyPass.cs:19
해결:
DepthNormalspass 제공(URP LitDepthNormalsPass 기반 권장)- custom DepthNormals 구현 시: normalWS/normalVS/인코딩 방식이 URP와 일치하는지 확인
관련:
24.2.4 TAA/모션블러/리프로젝션이 이상함(고스팅/번짐/흔들림)
증상:
- 고스팅이 심하거나, 움직일 때 잔상이 남음
핵심 원인:
MotionVectorspass 누락 또는 잘못된 velocity 출력
확인:
- URP 소비 태그:
<URP>/Runtime/Passes/MotionVectorRenderPass.cs:14(MotionVectors) - Frame Debugger에서
MotionVectorspass가 호출되는지 확인
해결:
MotionVectorspass 추가- Lit.shader처럼
ObjectMotionVectors.hlsl를#include_with_pragmas로 포함(pragma 누락 방지)
관련:
book/20-urp-pass-tags-and-lightmode-contract.mdsamples/urp/URP_LitCompatibleTemplate.shader
24.2.5 그림자가 안 생기거나(특정 재질만) 컷아웃 그림자가 깨짐
증상:
- 어떤 오브젝트는 그림자가 아예 없음
- 컷아웃(AlphaTest) 오브젝트의 그림자가 구멍이 안 뚫림/과도하게 뚫림
핵심 원인:
ShadowCasterpass 누락- ShadowCaster에서
_ALPHATEST_ON처리/컷오프 값이 ForwardLit과 불일치
확인:
- Frame Debugger/ShadowMap 렌더 단계에서 해당 오브젝트가 그려지는지 확인
- 셰이더에
LightMode=ShadowCasterpass가 있는지 확인
해결:
- 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에 고정하고, 조건부 컴파일로 구조가 바뀌지 않게 함
관련:
book/09-writing-urp-compatible-shaders.mdsamples/urp/URP_LitCompatibleTemplate.hlsl
24.2.7 Decal(DBuffer)이 특정 재질에서만 안 먹음
증상:
- 프로젝트에서 Decal은 켜져 있는데 특정 셰이더만 데칼이 적용되지 않음
핵심 원인:
ApplyDecalToSurfaceData(...)호출 경로가 없거나,_DBUFFERvariant가 없음
확인:
- 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.shader의XRMotionVectorspass 존재 여부 확인- Frame Debugger에서 XR 경로 pass 소비 확인
해결:
- URP Lit의 XR MotionVectors pass 구조를 기반으로 구현(Stencil/define 포함)
관련:
book/20-urp-pass-tags-and-lightmode-contract.mdsamples/urp/URP_LitCompatibleTemplate.shader
24.3 검색 레시피(원인 좁히기)
Generated를 먼저 보는 게 가장 빠릅니다.
- Pass/Include:
book/generated/urp-lit-map.md - 심볼 정의/xref:
book/generated/urp-17.3.0/xref/lit-key-symbols.md - 함수/구조체 인덱스:
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일 가능성이 높습니다.
- RenderGraph Viewer에서 해당 패스가 그래프에 존재하는지 확인
- 패스 출력 핸들이 다음 패스 입력으로 연결되는지 확인
- 카메라 컬러 교체 패턴이면 교체본이 후속 패스에서 소비되는지 확인
- 전역 바인딩만 있고 소비 경로가 없으면 임시 소비 패스를 붙여 생존성 확인
샘플 참고:
samples/Unity6_Rendering_Bible/04_Render_Graph_System/03_RecordRenderGraph_Migration_Checklist.mdsamples/Unity6_Rendering_Bible/04_Render_Graph_System/04_RenderGraph_Debugging_and_Culling.md