Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


Add a 2D custom render pass to the frame rendering loop in URP

Add and inject a custom render pass, and learn about the specific APIs you use in a 2D project.
Read time 3 minutesLast updated 21 days ago

A custom render pass is a way to change how the Universal Render Pipeline (URP) renders a scene or the objects within a 2D scene. A custom render pass contains your own rendering code, which you insert into the rendering pipeline at an injection point.
To add a custom render pass in a 2D project, refer to the documentation for 3D projects in Custom render pass workflow in URP.
In a 2D project, make the following changes:
  1. When you write a render pass, use the
    ScriptableRenderPass2D
    class instead of the
    ScriptableRenderPass
    class.
  2. When you inject a render pass using a Scriptable Renderer Feature, use the
    ScriptableRendererFeature2D
    class instead of the
    ScriptableRendererFeature
    class.
  3. To inject the render pass, use the
    renderPassEvent2D
    property to set a
    RenderPassEvent2D
    , instead of the
    renderPassEvent
    property. For a list of 2D injection points, refer to Injection points reference for 2D in URP.
To access the texture resources used by the URP 2D renderer, including the active 2D light and shadow textures, use the
Universal2DResourceData
API. For more information, refer to Frame data in the render graph system in URP.

Example

The following 2D Scriptable Renderer Feature contains an example render pass that creates a texture and clears it to yellow. For more information about adding the render pass to the render pipeline, refer to Add a Renderer Feature to a URP Renderer.
Use the Frame Debugger to check the texture the render pass adds.
using UnityEngine;using UnityEngine.Rendering.Universal;using UnityEngine.Rendering.RenderGraphModule;using UnityEngine.Rendering;// Create a 2D Scriptable Renderer Featurepublic class CreateYellowTextureFeature2D : ScriptableRendererFeature2D{ CreateYellowTexture customPass; public override void Create() { customPass = new CreateYellowTexture(); // Inject the render pass at a 2D injection point injectionPoint2D = RenderPassEvent2D.AfterRenderingPostProcessing; customPass.renderPassEvent2D = injectionPoint2D; customPass.renderPassSortingLayerID = sortingLayerID; } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { renderer.EnqueuePass(customPass); } // Create a 2D render pass class CreateYellowTexture : ScriptableRenderPass2D { class PassData { public TextureHandle cameraColorTexture; } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext) { using (var builder = renderGraph.AddRasterRenderPass<PassData>("Create yellow texture", out var passData)) { // Get the frame data UniversalResourceData frameData = frameContext.Get<UniversalResourceData>(); // Create texture properties that match the screen size TextureDesc textureDesc = frameData.activeColorTexture.GetDescriptor(renderGraph); textureDesc.msaaSamples = MSAASamples.None; // Create a temporary texture passData.cameraColorTexture = renderGraph.CreateTexture(textureDesc); // Set the texture as the render target builder.SetRenderAttachment(passData.cameraColorTexture, 0, AccessFlags.Write); // Make sure the render graph system keeps the render pass, even if it's not used in the final frame. // Don't use this in production code, because it prevents the render graph system from removing the render pass if it's not needed. builder.AllowPassCulling(false); builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => ExecutePass(data, context)); } } static void ExecutePass(PassData data, RasterGraphContext context) { // Clear the render target to yellow context.cmd.ClearRenderTarget(true, true, Color.yellow); } }}

Additional resources