book/22-urp-lit-callflow-and-edit-points.md

22. URP Lit Call Flow & Edit Points

The actual call flow of Unity 6.3 (6000.3) / URP 17.3.0 Lit Forward (UniversalForward) is fixed based on the source, and customization points that do not break compatibility are presented step by step.

This chapter is a practical guide to end “I studied URP Lit, but I don’t know where to fix it.”

  • Lit Forward (UniversalForward) Fixes the actual flow of the fragment to the “correct reference” and
  • Where to put customization so as not to break compatibility (=edit points)
  • What has a high risk of breaking immediately when touched (=risk points)?

We organize it step by step.

22.0 Accurate Reference (IDE)

The symbols/definitions/references in this chapter refer to the IDE references below as the primary source.

22.1 Fixed Lit Forward entry (definition location/signature)

As of URP 17.3.0:

  • LitPassVertex
    • Definition: <URP>/Shaders/LitForwardPass.hlsl:158
    • Signature: Varyings LitPassVertex(Attributes input)
  • LitPassFragment
    • Definition: <URP>/Shaders/LitForwardPass.hlsl:223
    • Core: void + out SV_Target* output

Output structure (summary) of LitPassFragment:

void LitPassFragment(
Varyings input,
out half4 outColor : SV_Target0
// + optional: outRenderingLayers : SV_Target1
)

Why not return half4?
For extending features such as MRT/Rendering Layers, the “keep output contract as out parameter” structure is safer.
Related: 16. URP Lit include 체인 맵

22.2 Actual call flow of Lit Forward (URP 17.3.0)

The core flow of URP 17.3.0 LitForwardPass is summarized below (exact call points are in xref):

  1. (Optional) Parallax / LODFade
  2. Configure SurfaceData with InitializeStandardLitSurfaceData
  3. Configure InputData with InitializeInputData
  4. (Optional) Decal(DBuffer)
  5. Prepare baked GI with InitializeBakedGIData etc.
  6. Lighting synthesis with UniversalFragmentPBR
  7. Output after Fog/Alpha processing

Core function definition location (URP 17.3.0):

SymbolReturnsDefined-in
InitializeStandardLitSurfaceDatavoid<URP>/Shaders/LitInput.hlsl:252
InitializeInputDatavoid<URP>/Shaders/LitForwardPass.hlsl:72
ApplyDecalToSurfaceDatavoid<URP>/ShaderLibrary/DBuffer.hlsl:191
InitializeBakedGIDatavoid<URP>/Shaders/LitForwardPass.hlsl:132
UniversalFragmentPBRhalf4<URP>/ShaderLibrary/Lighting.hlsl:282
MixFoghalf3/float3<URP>/ShaderLibrary/ShaderVariablesFunctions.hlsl:513
OutputAlphahalf<URP>/ShaderLibrary/ShaderVariablesFunctions.hlsl:239

Fix the flow with Mermaid:

flowchart TD A[LitPassFragment] --> B[InitializeStandardLitSurfaceData\n(SurfaceData)] A --> C[InitializeInputData\n(InputData)] B --> D{Feature hooks} C --> D D -->|Decal| E[ApplyDecalToSurfaceData] D -->|Baked GI| F[InitializeBakedGIData] E --> G[UniversalFragmentPBR] F --> G G --> H[MixFog / OutputAlpha] H --> I[SV_Target0 outColor]

22.3 Edit Points (Safe Customization Points) — “Where can I change something to make it less broken?”

URP Lit is tightly coupled with surrounding features (Forward+/Decal/Rendering Layers/GI/ShadowMixing, etc.). Therefore, the safest way to “customize while maintaining compatibility” is to adjust internal values ​​while maintaining the light loop/pass contract.

22.3.1 Edit Point A: Adjust SurfaceData (most secure)

Target:

  • surfaceData.albedo, surfaceData.normalTS, surfaceData.smoothness, surfaceData.emission, etc.

Advantages:

  • Material model can be changed while maintaining Pass contract/Forward+ loop/Shadow/GI coupling

Risk:

  • Low (however, when combined with alpha/_ALPHATEST_ON, ShadowCaster/DepthOnly needs to be checked)

Verification:

  • Check if ShadowCaster/DepthOnly/DepthNormals are normal together in Frame Debugger
  • Check whether SRP Batcher (material constant) is maintained (Chapter 09)

22.3.2 Edit Point B: Adjust InputData (medium difficulty)

Target:

  • inputData.normalWS, inputData.viewDirectionWS, inputData.shadowCoord, inputData.normalizedScreenSpaceUV, etc.

Advantages:

  • Easy to add view/space based effects (e.g. custom fresnel, view-dependent term)

Risk:

  • medium
    • In particular, messing with normalizedScreenSpaceUV may break the Forward+ cluster loop.

Verification:

  • Check if additional light is normal in Forward+ ON (Chapter 07)

22.3.3 Edit Point C: UniversalFragmentPBR Adjust color before/after (only when the purpose is clear)

Target:

  • Post-process the half4 color = UniversalFragmentPBR(...) results (rim, toon, custom tone) or
  • Expression for normalizing PBR input (e.g. roughness clamp)

Risk:

  • Medium to high
    • Physics-based assumptions may be broken and unexpected results may occur when combined with Debug Display/Decal/Rendering Layers.

Verification:

  • Check with Debug Display/Post Processing/Decal turned on

22.3.4 Risk Point: “Implement additional light loops yourself” (most risky)

In Forward+, there is a contract that GetAdditionalLightsCount() can be 0.

  • Definition: <URP>/ShaderLibrary/RealtimeLights.hlsl:271

So if you need to implement additional light loops yourself, at least use URP’s macros.

uint count = GetAdditionalLightsCount();
LIGHT_LOOP_BEGIN(count)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
// accumulate...
LIGHT_LOOP_END

More details: 07. Forward/Forward+/Lights

22.4 Edit Point Matrix (Summary)

change targetRecommended pointsCompatibility RiskBe sure to check together
Change material model (albedo/roughness/normal)SurfaceData EditlowShadowCaster/DepthOnly/DepthNormals
Add view dependent terms (rim/fresnel)InputData/PBR before and aftermiddleForward+ / XR / Fog
Lighting Model (BRDF) ReplacementUniversalFragmentPBR PathMedium to highAdditional Light Loops/Shadows/GI
Light Roof Self ReplacementDirect implementationHighLIGHT_LOOP_*, Forward+ Contract
Change Pass/Tag/OutputShaderLab Editvery highLightMode Consumption (Chapter 20)

22.5 Verification routine (required)

  1. Fix the definition position as ide: @@TOK_4_8394c928@@
  2. Frame Debugger: Check with which LightMode Pass my object is drawn.
  3. Compare Forward+ ON/OFF: Check whether the additional light is normal in both modes
  4. DepthNormals/MotionVectors: If the project has functions such as SSAO/TAA turned on, check whether the pass is actually consumed.

Troubleshooting Playbook: @@TOK_5_a2e9de9a@@