A custom render pass is a way to change how the Universal Render PipelineA series of operations that take the contents of a Scene, and displays them on a screen. Unity lets you choose from pre-built render pipelines, or write your own. More info
See in Glossary (URP) renders a sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary 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:
ScriptableRenderPass2D class instead of the ScriptableRenderPass class.ScriptableRendererFeature2D class instead of the ScriptableRendererFeature class.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.
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 Feature
public 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);
}
}
}