03. URP Architecture: Asset / Renderer / Feature / Pass
This chapter structurally organizes “Where should I put code to expand?” in URP. When writing a Render Feature/Pass, the goal is to have a sense of determining the Injection Point.
3.1 Components of URP
UniversalRenderPipelineAsset(URP global settings)ScriptableRenderer(actually configure/run camera rendering)ScriptableRendererFeature(extension point where the user “equips” functionality to the renderer)ScriptableRenderPass(unit of one render pass)
Typically, developers create RendererFeature, attach it to a renderer, create a pass within it, and insert it into the rendering pipeline.
3.1.1 (Important) Feature life cycle: Create / AddRenderPasses / SetupRenderPasses / Dispose
URP calls for ScriptableRendererFeature in approximately the following order:
Create()- Called at “configuration change points,” such as when a feature is loaded, toggled active/disabled, or an inspector value changes.
- In principle, create resources (material/path instance/buffer, etc.) here
AddRenderPasses(renderer, ref RenderingData)- Call once per frame, per camera
- “Register” the pass to the pipeline with
renderer.EnqueuePass(pass) - Caution: This function is called very frequently, so allocation/creation operations should not be performed.
SetupRenderPasses(renderer, in RenderingData)- “Setting” necessary values before executing the pass, including camera target (color/depth)
- The Unity document also guides you to access camera targets such as
cameraColorTargetfromSetupRenderPasses, notAddRenderPasses.
Dispose(bool)- Resources are released when the feature is destroyed
Rules of practice
- Create: “Create/initialize (once)”
- AddRenderPasses: “Determine which camera to apply + Enqueue”
- SetupRenderPasses: “Camera target/frame-specific parameter settings”
- Dispose: “Clean up”
Related official documents:
- Scriptable Renderer Feature Workflow (Custom Pass/Injection Flow): https://docs.unity3d.com/kr/6000.3/Manual/urp/inject-a-render-pass.html
- Unity 6 (URP 17) Upgrade Guide (Change Camera Target Approach Location): https://docs.unity3d.com/jp/current/Manual/urp/upgrade-guide-unity-6.html
3.2 Where do I insert the pass? (RenderPassEvent)
URP expresses the timing at which the pass will be executed as an event enumeration (e.g. before/after Opaque, before/after Transparent, before/after Post, etc.).
The most common timings in practice:
- “After Opaque, before Transparent”: Screen-based effects/depth-based effects
- “Immediately before/immediately after post”: color grading/blur/outline, etc.
In the RenderGraph path, events alone may not be enough, and the actual dependency is determined by “which resource is being read/written”. (RenderGraph is 04. RenderGraph)
3.2.1 Practical criteria for selecting an injection point
When designing a renderer feature, determining the injection point (=pass execution timing) by asking the following questions will reduce mistakes.
- What is an input texture?
- Color that reflects only opaque? Colors that include transparent?
- Is Depth/Normals necessary?
- Where will the output go?
- Overwrite camera color?
- Used for temporary RT and then synthesized?
- What do subsequent passes expect?
- Should it be applied before post-processing? Should I apply it later?
- Is it safe for XR/Dynamic Resolution/Multiple Cameras?
- Does each camera use a different target/scale?
The most common mistake is “event-only” timing.
In RenderGraph, resource dependencies (read/write declarations) determine the actual order more strongly than events.
3.2.2 Revisiting injection timing with the Unity 6 frame lifecycle
RenderPassEvent is a hint that determines “when to execute,” and in practice, it is safe to look at the frame stage and input resource preparation status together. |
frame steps | General Purpose | Recommended Event (Example) | Common Mistakes |
|---|---|---|---|---|
| After Setup/Culling | Check frame input readiness | BeforeRenderingPrePasses Series |
Forced on cameras without Depth/Normals | |
| After Depth Prepass | Depth based effects | AfterRenderingPrePasses |
Raw depth linearization missing | |
| After Opaque | Silhouette/Mask/Distortion Ready | AfterRenderingOpaques |
Afterwards, only output is generated without any consumption pass | |
| After Transparent | Screen distortion/compositing | AfterRenderingTransparents |
Missing transparent sorting/sorting assumptions | |
| Before/After Post | Final Tone/Screen Cover | Before/AfterRenderingPostProcessing |
UI/Overlay camera influence range undefined |
3.3 Compatibility Mode vs RenderGraph
There are two ways to create a URP custom pass.
- Compatibility Mode: Direct drawing from
Execute()toCommandBuffer(legacy approach) - RenderGraph Path: “Declare” paths and resource dependencies in
RecordRenderGraph()(current/recommended)
The URP documentation also emphasizes that RenderGraph-based path writing is the focus, and non-RenderGraph paths are no longer actively developed.
3.4 Minimal motion example (skeleton)
Below is a skeleton showing only the structure. An actual RenderGraph pass example is covered in 04. RenderGraph.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public sealed class ExampleFeature : ScriptableRendererFeature
{
sealed class ExamplePass : ScriptableRenderPass
{
// RenderGraph 경로(권장)
public override void RecordRenderGraph(UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph,
ContextContainer frameData)
{
// TODO: renderGraph.AddRasterRenderPass(...) 등으로 패스 선언
}
// Compatibility Mode 경로(레거시)
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// TODO: CommandBufferPool.Get/Release, Blit, DrawRenderer 등
}
}
ExamplePass _pass;
public override void Create()
{
_pass = new ExamplePass();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(_pass);
}
}
3.4.1 Application by camera type (required for practice)
URP renders multiple camera types including scene view/game view/preview/reflection. In practice, it is usually applied “only to the game camera” or “scene view is only for debugging”.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderingData.cameraData.cameraType != CameraType.Game)
return;
renderer.EnqueuePass(_pass);
}
3.5 Designing Pass Structure as ‘Texture Requirements’
The URP pass must declare “this pass requires some textures/input”.
- If Depth is needed, DepthTexture creation may be necessary.
- If Normal is needed, the DepthNormals pass may have to be done first.
- If Motion Vector/History is needed, a separate request arises.
In the RenderGraph path, these requests are structured in the form of UniversalResourceData/Frame Data, and in features such as Full Screen Pass, these are specified as “Requirements.”
Related documents:
- Full Screen Pass Renderer Feature (Requirements concept): https://docs.unity3d.com/Manual/urp/renderer-features/renderer-feature-full-screen-pass.html
3.6 RenderGraph Era Renderer Feature Design Checklist
3.6.1 Resource Readiness/Lifetime
- Don't assume Depth/Normals/MotionVectors are always ready for all cameras.
- Texture format (sRGB/Linear), Render Scale, and DRS should be included in the input contract.
- If external RT is imported (
ImportTexture), document the life subject (graph/external) boundary.
3.6.2 Pass Culling Survivability
RenderGraph can remove a pass if “the output does not lead to the final result.”
- Ensure that the output handle is actually read in subsequent passes
- Designed so that even debug passes do not rely solely on side effects (global binding, etc.)
- The mask creation pass is verified by combining it with the next synthesis pass.
3.6.3 Camera Stack/Multi-Camera Stability
- Global texture key (
SetGlobalTexture) has a high risk of multi-camera collision - Separate Base/Overlay camera paths and specify application conditions
- Safe shutdown with early-out in cameras without input (e.g. depth not generated)
3.7 Sample-based reference notes
We incorporated the concepts from the sample document below into the design criteria for this chapter.
samples/Unity6_Rendering_Bible/01_Architecture_and_Pipeline/02_URP_Lifecycle.mdsamples/Unity6_Rendering_Bible/01_Architecture_and_Pipeline/04_URP_Renderer_Features_Design.mdsamples/Unity6_Rendering_Bible/04_Render_Graph_System/03_RecordRenderGraph_Migration_Checklist.md
Further reading (official/authoritative sources)
- Create URP RenderGraph pass (Compatibility Mode): https://docs.unity3d.com/Manual/urp/render-graph-write-render-pass-compatibility.html
- Injecting paths with the Scriptable Renderer Feature (tutorial): https://docs.unity3d.com/kr/6000.3/Manual/urp/inject-a-render-pass.html