book/16-urp-shaderlibrary-lit-include-chain.md

16. URP ShaderLibrary 실제 맵: Lit 기준 include 체인

Unity 6.3(6000.3) + URP(17.x)에서 Lit.shader를 기준으로 어떤 HLSL 파일/함수/키워드가 어떻게 연결되는지 ‘실제 소스 기반’으로 지도화한다

이 챕터의 목표는 다음 질문들에 “경로를 잃지 않고” 답할 수 있게 만드는 것입니다.

  • URP Lit.shader는 어떤 패스(LightMode)들로 구성되어 있는가?
  • 각 패스는 어떤 .hlsl을 include하고, 거기서 어떤 엔트리 함수(vertex/fragment)가 정의되는가?
  • TransformObjectToHClip, GetMainLight, UniversalFragmentPBR 같은 함수는 어느 파일에서 오는가?

매우 중요
URP는 패키지 버전이 바뀌면 파일 구성/함수 이름이 조금씩 바뀝니다.
이 문서는 URP Lit를 기준으로 “역할/연결 구조” 를 고정해 이해하도록 돕고, 최종 확인은 로컬 패키지 소스로 하도록 설계합니다.

16.0 정확 레퍼런스(IDE, URP 17.3.0)

이 챕터의 “정확성 앵커(anchor)”는 IDE surface입니다.

원칙: “정의 위치(파일/라인)”는 IDE Index가 1차 진입점입니다.
맥락(왜 그렇게 구현됐나)은 로컬 URP/Core 소스를 열어 읽습니다.

선행:

16.1 먼저 버전을 고정하자(“Unity 6.3”의 실체)

Unity 6.3은 보통 6000.3.* 에디터 버전을 의미하지만, 셰이더 include 체인은 URP 패키지 버전에 의해 결정됩니다.

실무 체크:

  1. Package Manager에서 com.unity.render-pipelines.universal 버전을 확인
  2. 로컬 패키지 소스를 열어서(Packages/ 또는 Library/PackageCache/) 실제 파일을 확인

관련: 01. 큰그림

16.2 Lit.shader는 “패스 묶음”이다(URP 17.3.0: LightMode 9종)

URP Lit.shader는 “Lit 머티리얼”이 파이프라인의 여러 단계에 참여할 수 있도록 여러 ShaderLab Pass의 묶음으로 구성됩니다.

URP 17.3.0의 Lit.shader에는 아래 9개 LightMode Pass가 존재합니다(정확 목록/Include는 /ide/graph/ 참고).

Pass NameLightMode언제 소비되나(요약)
ForwardLitUniversalForward기본 Forward 컬러(Forward+ 포함)
GBufferUniversalGBufferDeferred 렌더링에서 GBuffer 출력
ShadowCasterShadowCaster그림자 맵 렌더링
DepthOnlyDepthOnly카메라 Depth/깊이 프리패스
DepthNormalsDepthNormalsDepth+Normals 텍스처 생성(SSAO/Outline 기반)
MetaMeta라이트맵 베이킹용
MotionVectorsMotionVectors오브젝트 모션 벡터(velocity)
XRMotionVectorsXRMotionVectorsXR 모션 벡터(+스텐실 계약 포함)
Universal2DUniversal2D2D Renderer 호환 패스

이 pass들은 URP의 Render Pass(=C# 파이프라인 단계)가 “특정 LightMode를 가진 ShaderLab Pass”를 찾을 때 선택됩니다.

관련: 09. URP 호환 셰이더 작성

16.3 Lit 기준 “include 체인” 큰 지도

Lit 계열 셰이더의 include는 크게 3층으로 생각하면 안정적입니다.

  1. Core 층(기반): 좌표 변환/플랫폼 매크로/유틸/정의
  2. 기능 층(입력/라이팅/쉐도우/GI): 라이트 접근, BRDF, 그림자 샘플링, 라이트맵/프로브
  3. 패스 층(엔트리): Forward/Depth/Shadow/Meta의 vertex/fragment 엔트리 함수

16.3.1 Mermaid로 보는 체인(개념 지도)

이 그래프는 “어떤 역할이 어디에 연결되는지”를 표현합니다.
정확한 파일명은 URP 버전에서 다를 수 있으니, 그래프를 따라 로컬 패키지에서 확인하세요.

graph TD LitShader["Lit.shader (ShaderLab)"] %% Pass blocks (LightMode) ForwardPass["ForwardLit (UniversalForward)"] GBufferPass["GBuffer (UniversalGBuffer)"] ShadowPass["ShadowCaster (ShadowCaster)"] DepthOnlyPass["DepthOnly (DepthOnly)"] DepthNormalsPass["DepthNormals (DepthNormals)"] MetaPass["Meta (Meta)"] MotionPass["MotionVectors (MotionVectors)"] XRMotionPass["XRMotionVectors (XRMotionVectors)"] Pass2D["Universal2D (Universal2D)"] %% URP pass HLSL (entry/include roots) LitForward["LitForwardPass.hlsl (LitPassVertex/LitPassFragment)"] LitGBuffer["LitGBufferPass.hlsl (LitGBufferPassVertex/LitGBufferPassFragment)"] LitInput["LitInput.hlsl (Surface/Material 입력)"] LitMeta["LitMetaPass.hlsl (Meta 엔트리)"] LitDepthNormals["LitDepthNormalsPass.hlsl (DepthNormals 엔트리)"] DepthOnlyHlsl["DepthOnlyPass.hlsl (DepthOnly 엔트리)"] ShadowCasterHlsl["ShadowCasterPass.hlsl (ShadowCaster 엔트리)"] ObjectMotion["ObjectMotionVectors.hlsl (MotionVectors 엔트리)"] Universal2D["Utils/Universal2D.hlsl (2D 엔트리)"] %% Core/Lighting Core["Core.hlsl / SpaceTransforms / UnityInput"] Surface["SurfaceInput.hlsl (BaseMap/NormalMap 등)"] Lights["Lighting.hlsl / RealtimeLights.hlsl"] Shadows["Shadows.hlsl"] GI["GlobalIllumination.hlsl (SAMPLE_GI 등)"] LitShader --> ForwardPass --> LitForward LitShader --> GBufferPass --> LitGBuffer LitShader --> ShadowPass --> ShadowCasterHlsl LitShader --> DepthOnlyPass --> DepthOnlyHlsl LitShader --> DepthNormalsPass --> LitDepthNormals LitShader --> MetaPass --> LitMeta LitShader --> MotionPass --> ObjectMotion LitShader --> XRMotionPass --> ObjectMotion LitShader --> Pass2D --> Universal2D LitForward --> LitInput LitGBuffer --> LitInput ObjectMotion --> LitInput Universal2D --> LitInput LitForward --> Core LitForward --> Surface LitForward --> Lights LitForward --> Shadows LitForward --> GI

이 지도를 기준으로, 함수가 어디서 오는지 추적합니다.

16.4 Pass별 “엔트리 함수”와 주요 책임(URP 17.3.0)

URP 셰이더에서 가장 중요한 것은 “각 Pass가 어떤 엔트리/출력을 책임지는가(=계약)”입니다.

Pass NameLightMode엔트리(대표)핵심 책임(요약)
ForwardLitUniversalForwardLitPassVertex / LitPassFragmentSurfaceData/InputData 구성 → PBR 합성 → Fog/Alpha → SV_Target* 출력
GBufferUniversalGBufferLitGBufferPassVertex / LitGBufferPassFragmentDeferred용 GBuffer 출력
ShadowCasterShadowCasterShadowPassVertex / ShadowPassFragment그림자 맵 depth 기록(+알파 클립/바이어스)
DepthOnlyDepthOnlyDepthOnlyVertex / DepthOnlyFragmentdepth 기록(+알파 클립)
DepthNormalsDepthNormalsDepthNormalsVertex / DepthNormalsFragmentdepth+normal 기록(SSAO/outline 기반)
MetaMetaUniversalVertexMeta / UniversalFragmentMetaLit베이킹용 meta 출력(알베도/에미션 중심)
MotionVectorsMotionVectors(ObjectMotionVectors 제공 엔트리)velocity 출력(ColorMask RG)
XRMotionVectorsXRMotionVectors(ObjectMotionVectors 제공 엔트리)XR velocity 출력(+스텐실 계약)
Universal2DUniversal2Dvert / frag(Universal2D)2D Renderer 호환 컬러 패스

실무 포인트
“완전 호환”은 단순히 ForwardLit만 되는 상태가 아니라, 프로젝트가 실제로 소비하는 LightMode Pass를 제공하는 상태입니다.
계약 전체 표(언제/왜 소비되는가): book/20-urp-pass-tags-and-lightmode-contract.md

관련: 09. URP 호환 셰이더 작성

16.5 Lit Forward(UniversalForward)를 “정확 레퍼런스”로 고정하기

Lit Forward는 URP에서 가장 많이 커스터마이즈되는 영역이므로, 아래 심볼들은 반드시 시그니처/반환값/정의 위치까지 고정해 두는 것을 권장합니다.

원본: /ide/index/

16.5.1 핵심 심볼(반환값/정의 위치)

SymbolReturnsParams(요약)Defined-in
TransformObjectToHClipfloat4float3 positionOS<CORE>/ShaderLibrary/SpaceTransforms.hlsl:108
LitPassVertexVaryingsAttributes input<URP>/Shaders/LitForwardPass.hlsl:158
LitPassFragmentvoidout SV_Target* 출력<URP>/Shaders/LitForwardPass.hlsl:223
InitializeStandardLitSurfaceDatavoidfloat2 uv, out SurfaceData<URP>/Shaders/LitInput.hlsl:252
InitializeInputDatavoidVaryings, normalTS, out InputData<URP>/Shaders/LitForwardPass.hlsl:72
UniversalFragmentPBRhalf4InputData, SurfaceData<URP>/ShaderLibrary/Lighting.hlsl:282

16.5.2 LitPassFragmenthalf4 return이 아닌 이유: out SV_Target(MRT/Rendering Layers)

URP 17.3.0에서 LitPassFragment는 반환값 대신 SV_Target0(및 조건부 SV_Target1)를 out 파라미터로 출력합니다.

  • 정의: <URP>/Shaders/LitForwardPass.hlsl:223

이 형태는:

  • MRT(렌더 타겟 다중 출력)로 확장 가능한 형태를 유지하고,
  • Rendering Layers 같은 기능이 켜졌을 때 추가 출력을 붙이기 쉽고,
  • “완전 호환” 커스텀 셰이더가 URP 기능과 결합될 가능성을 높입니다.

16.5.3 Lit Forward 호출 흐름(단계 고정)

URP Lit Forward 프래그먼트는 대체로 아래 순서로 구성됩니다(정확 호출 지점은 IDE Index로 고정).

  1. InitializeStandardLitSurfaceData — UV/텍스처로 SurfaceData 구성
  2. InitializeInputData — Varyings/normalTS로 InputData 구성
  3. (옵션) Decal/GI/APV 등 주변 기능 결합
  4. UniversalFragmentPBR — 메인/추가 라이트/그림자/GI 합성
  5. MixFog, OutputAlpha 등 후처리 후 SV_Target* 출력
flowchart TD A[LitPassFragment] --> B[InitializeStandardLitSurfaceData] B --> C[InitializeInputData] C --> D{Feature hooks} D -->|Decal| E[ApplyDecalToSurfaceData] D -->|Baked GI| F[InitializeBakedGIData] E --> G[UniversalFragmentPBR] F --> G G --> H[MixFog / OutputAlpha] H --> I[SV_Target0 outColor]

16.5.4 Forward+ 루프 분기(요약)

Forward+에서는 추가 라이트 루프 계약이 달라집니다.

  • GetAdditionalLightsCount()가 0을 반환할 수 있습니다(계약).
    • 정의: <URP>/ShaderLibrary/RealtimeLights.hlsl:271
  • URP는 LIGHT_LOOP_BEGIN/END로 Forward/Forward+ 루프를 동시에 만족시킵니다.
    • 정의: <URP>/ShaderLibrary/RealtimeLights.hlsl:28 / :36

자세한 내용/디버깅 루틴: 07. Forward/Forward+/Lights

16.6 SurfaceData vs InputData: “무엇을 어디에 넣는가”

URP Lit를 이해하는 가장 좋은 기준은 이 두 구조체를 분리해 암기하는 것입니다.

16.6.1 SurfaceData(표면/재질 입력)

SurfaceData는 “머티리얼이 어떤 표면인가”에 대한 정보입니다.

  • 알베도(Base Color/Base Map)
  • 노말(Normal Map)
  • 메탈릭/스무스니스/오클루전/에미션
  • 알파/컷오프

즉, 텍스처 샘플링과 머티리얼 파라미터 정리가 핵심입니다.

16.6.2 InputData(공간/카메라/조명 입력)

InputData는 “그 표면이 씬에서 어디에 있고, 어떤 카메라/조명 조건인지” 정보입니다.

  • positionWS / normalWS / viewDirectionWS
  • shadowCoord
  • fogCoord
  • bakedGI / shadowMask
  • normalizedScreenSpaceUV

즉, 공간/좌표/카메라/그림자/GI 준비가 핵심입니다.

이 분리를 이해하면:

  • “표면 모델을 바꾸고 싶다” → SurfaceData 생성/변형 쪽
  • “라이팅 계산을 바꾸고 싶다” → PBR 함수 또는 라이트 접근 쪽
  • “깊이/스크린 UV가 필요하다” → InputData/코어 유틸 쪽

으로 빠르게 방향을 잡을 수 있습니다.

16.7 “정확 레퍼런스”를 로컬에서 재생성하는 방법(추천)

이 책은 “원본(패키지 소스)”을 기준으로 학습하는 것을 목표로 하므로, viewer-v2 데이터를 재생성한 뒤 IDE에서 include/심볼/xref를 탐색하는 워크플로를 제공합니다.

  • 원클릭 러너: tools/generate-all.mjs
  • 생성 데이터 루트: book/public/generated/<version>/viewer-v2/
  • 사용법/탐색 entry: /ide/docs/

tools/generate-all.mjs는 다음을 순서대로 수행합니다.

  1. viewer-v2 manifest/file/chunk 데이터 생성
  2. 검증 스크립트로 schema 4 산출물 검사
  3. IDE에서 /ide/graph/, /ide/index/, /ide/docs/를 통해 결과 탐색

실행(예시):

Terminal window
node tools/generate-all.mjs --unity-project-root "<YOUR_UNITY_PROJECT_ROOT>"

생성물은 절대 경로를 그대로 노출하지 않고 <URP>, <CORE>로 치환합니다.

참고
수동 유지보수 성격의 보조 스크립트는 기본 파이프라인에서 제외되어 tools/manual/** 아래로 분리됩니다.
일상적인 갱신은 tools/generate-all.mjs 또는 pnpm gen:all을 기본 루틴으로 사용합니다.

16.8 다음으로 무엇을 보면 좋은가?

16.9 실습 과제(추천)

  1. tools/generate-all.mjs 실행 후 /ide/graph/를 연다.
  2. ForwardLit (UniversalForward) 섹션에서 include 목록을 본다.
  3. /ide/index/에서 다음을 “정의 위치 → 호출처”로 추적한다.
    • LitPassFragment
    • InitializeStandardLitSurfaceData
    • InitializeInputData
    • UniversalFragmentPBR
  4. Frame Debugger로 “DepthNormals pass가 언제 호출되는지”를 실제 프레임에서 확인한다.