Rasagar/Library/PackageCache/com.unity.render-pipelines.universal/Documentation~/renderer-features/write-a-scriptable-render-pass.md
2024-08-26 23:07:20 +03:00

8.7 KiB

uid
urp-write-a-scriptable-render-pass

Write a Scriptable Render Pass in Compatibility Mode

[!include]

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

  1. Creates a temporary render texture using the RenderTextureDescriptor API.
  2. Applies two passes of the custom shader to the camera 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 Blit method to apply the two render passes from the custom shader 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
        }
    }
}