Write a render pass using the render graph system in SRP Core
Write a render pass using the render graph system, after you use the BeginRecording API to start recording render graph commands.
Note: This section is about creating a custom render pipeline. To use the render graph system in a prebuilt Unity pipeline, refer to either Render graph system in URP or Render graph system in HDRP.
Prerequisites
To add a render pass, you must first create a render graph instance and start recording. For more information, refer to Write a render pipeline with render graph.
Write a render pass
Create a class or struct that declares the resources the render pass uses. For example:
class PassData { public TextureHandle cameraTarget; public TextureHandle sourceTexture; }Ensure that you declare only the variables that the render pass uses. Adding unnecessary variables can reduce performance.
Declare the render pass, for example using the
AddRasterRenderPassmethod.using (var builder = myRenderGraph.AddRasterRenderPass<PassData>("Example render pass", out var passData)) { }The
buildervariable is an instance of theIRasterRenderGraphBuilderinterface. This variable is the entry point for configuring the information related to the render pass.Set the resources that the render pass uses. For example:
using (var builder = myRenderGraph.AddRasterRenderPass<PassData>("Example render pass", out var passData)) { ... // Set the source texture as the camera target. passData.cameraTarget = myRenderGraph.ImportBackbuffer(BuiltinRenderTextureType.CameraTarget, cameraTargetProperties); // Set the destination texture as a temporary texture. passData.sourceTexture = myRenderGraph.CreateTexture(textureProperties); }For more information, refer to Resources in the render graph system.
Declare the inputs of the render pass using the
UseTextureAPI, but don't add commands to command buffers. This is the recording stage.builder.UseTexture(passData.cameraTarget, AccessFlags.Read);Declare the output of the render pass using the
SetRenderAttachmentAPI. For example:builder.SetRenderAttachment(passData.sourceTexture, 0, AccessFlags.Write);To add commands, declare a rendering function using the
SetRenderFuncAPI. Use a static method or a static lambda method. This is the execution stage. For example:builder.SetRenderFunc(static (PassData passData, RasterGraphContext context) => { context.cmd.ClearRenderTarget(true, true, Color.blue); });
Example
The following example sets a temporary texture as the input and the camera target as the output, then clears the camera target to blue. To use the example, add it to a custom render pipeline after the BeginRecording API. For more information, refer to Write a render pipeline with render graph.
This code example is simplified. It demonstrates the clearest workflow, rather than the most efficient runtime performance.
using (var builder = myRenderGraph.AddRasterRenderPass<PassData>("Example render pass", out var passData))
{
RenderTargetInfo cameraTargetProperties = new RenderTargetInfo
{
width = cameraToRender.pixelWidth,
height = cameraToRender.pixelHeight,
volumeDepth = 1,
msaaSamples = 1,
format = GraphicsFormat.R8G8B8A8_UNorm
};
passData.cameraTarget = myRenderGraph.ImportBackbuffer(BuiltinRenderTextureType.CameraTarget, cameraTargetProperties);
var textureProperties = new TextureDesc(Vector2.one)
{
colorFormat = GraphicsFormat.R8G8B8A8_UNorm,
width = cameraTargetProperties.width,
height = cameraTargetProperties.height,
clearBuffer = true,
clearColor = Color.red,
name = "My temporary texture"
};
passData.sourceTexture = myRenderGraph.CreateTexture(textureProperties);
passData.material = new Material(Shader.Find("Unlit/Texture"));
builder.UseTexture(passData.sourceTexture, AccessFlags.Read);
builder.SetRenderAttachment(passData.cameraTarget, 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 passData, RasterGraphContext context) =>
{
// Create a quad mesh
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(1f, 0, 0),
new Vector3(0, 1f, 0),
new Vector3(1f, 1f, 0)
};
mesh.vertices = vertices;
int[] triangles = new int[6]
{
0, 2, 1,
2, 3, 1
};
mesh.triangles = triangles;
context.cmd.ClearRenderTarget(true, true, Color.blue);
// Pass the source texture to the shader
passData.material.SetTexture("_MainTex", passData.sourceTexture);
// Create a transformation matrix for the quad
Matrix4x4 trs = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 0, 0), Vector3.one);
// Draw the quad onto the camera target, using the shader and the source texture
context.cmd.DrawMesh(mesh, trs, passData.material, 0);
});
}