Version: Unity 6 Preview (6000.0)
Language : English
Compatibility Mode in URP
Example of a complete Scriptable Renderer Feature in Compatibility Mode in URP

Write a Scriptable Render Pass in Compatibility Mode in URP

Note: Unity no longer develops or improves the rendering path that doesn’t use the render graph API. Use the render graph API instead when developing new graphics features. To use the instructions on this page, enable Compatibility Mode (Render Graph Disabled) in URP graphics settings (Project Settings > Graphics).

The following example is a ScriptableRenderPass instance that performs the following steps:

  1. Creates a temporary render textureA special type of Texture that is created and updated at runtime. To use them, first create a new Render Texture and designate one of your Cameras to render into it. Then you can use the Render Texture in a Material just like a regular Texture. More info
    See in Glossary
    using the RenderTextureDescriptor API.
  2. Applies two passes of the custom shader to the cameraA component which creates an image of a particular viewpoint in your scene. The output is either drawn to the screen or captured as a texture. More info
    See in Glossary
    output using the RTHandle and the Blit API.

After you write a Scriptable Render Pass, you can inject the render pass using one of the following methods:

Create the scriptable Render Pass

This section demonstrates how to create a scriptable Render Pass.

  1. Create a new C# script and name it RedTintRenderPass.cs.

  2. In the script, remove the code that Unity inserted in the RedTintRenderPass class. Add the following using directive:

    using UnityEngine.Rendering;
    using UnityEngine.Rendering.Universal;
    
  3. Create the RedTintRenderPass class that inherits from the ScriptableRenderPass class.

    public class RedTintRenderPass : ScriptableRenderPass
    
  4. Add the Execute method to the class. Unity calls this method every frame, once for each camera. This method lets you implement the rendering logic of the scriptable Render Pass.

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    { }
    

Below is the complete code for the RedTintRenderPass.cs file from this section.

using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RedTintRenderPass : ScriptableRenderPass
{
    public override void Execute(ScriptableRenderContext context,
        ref RenderingData renderingData)
    {
        
    }
}

Implement the settings for the custom render pass

  1. Add a field for the Material, and the constructor that uses the field.

    private Material material;
    
    public RedTintRenderPass(Material material)
    {
        this.material = material;
    }
    
  2. Add the RenderTextureDescriptor field and initialize it in the constructor:

    using UnityEngine;
    
    private RenderTextureDescriptor textureDescriptor;
    
    public RedTintRenderPass(Material material)
    {
        this.material = material;
    
        textureDescriptor = new RenderTextureDescriptor(Screen.width,
            Screen.height, RenderTextureFormat.Default, 0);
    }
    
  3. Declare the RTHandle field to store the reference to the temporary red tint texture.

    private RTHandle textureHandle;
    
  4. Implement the Configure method. Unity calls this method before executing the render pass.

    public override void Configure(CommandBuffer cmd,
        RenderTextureDescriptor cameraTextureDescriptor)
    {
        //Set the red tint texture size to be the same as the camera target size.
        textureDescriptor.width = cameraTextureDescriptor.width;
        textureDescriptor.height = cameraTextureDescriptor.height;
    
        //Check if the descriptor has changed, and reallocate the RTHandle if necessary.
        RenderingUtils.ReAllocateIfNeeded(ref textureHandle, textureDescriptor);
    }
    
  5. Use the BlitA shorthand term for “bit block transfer”. A blit operation is the process of transferring blocks of data from one place in memory to another.
    See in Glossary
    method to apply the two render passes from the custom shaderA program that runs on the GPU. More info
    See in Glossary
    to the camera output.

    public override void Execute(ScriptableRenderContext context,
        ref RenderingData renderingData)
    {
        //Get a CommandBuffer from pool.
        CommandBuffer cmd = CommandBufferPool.Get();
    
        RTHandle cameraTargetHandle =
            renderingData.cameraData.renderer.cameraColorTargetHandle;
    
        // Blit from the camera target to the temporary render texture,
        // using the first shader pass.
        Blit(cmd, cameraTargetHandle, textureHandle, material, 0);
        // Blit from the temporary render texture to the camera target,
        // using the second shader pass.
        Blit(cmd, textureHandle, cameraTargetHandle, material, 1);
    
        //Execute the command buffer and release it back to the pool.
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
    
  6. Implement the Dispose method that destroys the Material and the temporary render texture after the render pass execution.

    public void Dispose()
    {
        #if UNITY_EDITOR
                if (EditorApplication.isPlaying)
                {
                    Object.Destroy(material);
                }
                else
                {
                    Object.DestroyImmediate(material);
                }
        #else
                Object.Destroy(material);
        #endif
            
        if (textureHandle != null) textureHandle.Release();
    }
    

Custom render pass code

Below is the complete code for the custom Render Pass script.

using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RedTintRenderPass : ScriptableRenderPass
{
    private Material material;

    private RenderTextureDescriptor textureDescriptor;
    private RTHandle textureHandle;

    public RedTintRenderPass(Material material)
    {
        this.material = material;

        textureDescriptor = new RenderTextureDescriptor(Screen.width,
            Screen.height, RenderTextureFormat.Default, 0);
    }

    public override void Configure(CommandBuffer cmd,
        RenderTextureDescriptor cameraTextureDescriptor)
    {
        // Set the texture size to be the same as the camera target size.
        textureDescriptor.width = cameraTextureDescriptor.width;
        textureDescriptor.height = cameraTextureDescriptor.height;

        // Check if the descriptor has changed, and reallocate the RTHandle if necessary
        RenderingUtils.ReAllocateIfNeeded(ref textureHandle, textureDescriptor);
    }

    public override void Execute(ScriptableRenderContext context,
        ref RenderingData renderingData)
    {
        //Get a CommandBuffer from pool.
        CommandBuffer cmd = CommandBufferPool.Get();

        RTHandle cameraTargetHandle =
            renderingData.cameraData.renderer.cameraColorTargetHandle;

        // Blit from the camera target to the temporary render texture,
        // using the first shader pass.
        Blit(cmd, cameraTargetHandle, textureHandle, material, 0);
        // Blit from the temporary render texture to the camera target,
        // using the second shader pass.
        Blit(cmd, textureHandle, cameraTargetHandle, material, 1);

        //Execute the command buffer and release it back to the pool.
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    public void Dispose()
    {
    #if UNITY_EDITOR
        if (EditorApplication.isPlaying)
        {
            Object.Destroy(material);
        }
        else
        {
            Object.DestroyImmediate(material);
        }
    #else
            Object.Destroy(material);
    #endif

        if (textureHandle != null) textureHandle.Release();
    }
}

The custom shader for the red tint effect

This section contains the code for the custom shader that implements the red tint effect.

Shader "CustomEffects/RedTint"
{
    HLSLINCLUDE
    
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        // The Blit.hlsl file provides the vertex shader (Vert),
        // the input structure (Attributes), and the output structure (Varyings)
        #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"

    
        float4 RedTint (Varyings input) : SV_Target
        {
            float3 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, input.texcoord).rgb;
            return float4(1, color.gb, 1);
        }

        float4 SimpleBlit (Varyings input) : SV_Target
        {
            float3 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, input.texcoord).rgb;
            return float4(color.rgb, 1);
        }
    
    ENDHLSL
    
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
        LOD 100
        ZTest Always ZWrite Off Cull Off
        Pass
        {
            Name "RedTint"

            HLSLPROGRAM
            
            #pragma vertex Vert
            #pragma fragment RedTint
            
            ENDHLSL
        }
        
        Pass
        {
            Name "SimpleBlit"

            HLSLPROGRAM
            
            #pragma vertex Vert
            #pragma fragment SimpleBlit
            
            ENDHLSL
        }
    }
}
Compatibility Mode in URP
Example of a complete Scriptable Renderer Feature in Compatibility Mode in URP