知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【Unity Shader】SwapBuffer #119

はじめに

今回はURP12で追加されたSwapBufferを解説します。

Unity 2021.3.6f1
Universal RP 12.1.7

ソースコード

ScriptableRendererFeature

using UnityEngine;
using UnityEngine.Rendering.Universal;

namespace SwapBuffer
{
    public class GrayscaleRendererFeatureBySwapBuffer : ScriptableRendererFeature
    {
        [SerializeField]
        private Shader shader;

        private GrayscalePassBySwapBuffer grayscalePass;

        // 初期化
        public override void Create()
        {
            grayscalePass = new GrayscalePassBySwapBuffer(shader);
        }

        // 1つ、または複数のパスを追加する
        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            renderer.EnqueuePass(grayscalePass);
        }
    }
}

ScriptableRenderPass

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

namespace SwapBuffer
{
    public class GrayscalePassBySwapBuffer : ScriptableRenderPass
    {
        private const string ProfilerTag = nameof(GrayscalePassBySwapBuffer);

        private readonly Material material;

        public GrayscalePassBySwapBuffer(Shader shader)
        {
            material = CoreUtils.CreateEngineMaterial(shader);
            renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
        }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            var cmd = CommandBufferPool.Get(ProfilerTag);
            // Blit1回で良くなった
            Blit(cmd, ref renderingData, material);
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }
}

シェーダー

Shader "SwapBuffer/GrayScale"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "Renderpipeline"="UniversalPipeline" }

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float2 uv : TEXCOORD0;
                float4 positionHCS : SV_POSITION;
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);

            CBUFFER_START(UnityPerMaterial)
            float4 _MainTex_ST;
            CBUFFER_END

            Varyings vert (Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
                return OUT;
            }

            half4 frag (Varyings IN) : SV_Target
            {
                half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
                half gray = dot(col.rgb, half3(0.299, 0.587, 0.114));
                return half4(gray, gray, gray, col.a);
            }
            ENDHLSL
        }
    }
}

SwapBufferとは

一言でいうと、ポストエフェクトを楽に書ける機能のことになります。

以前のバージョンのURPですと、ポストエフェクトを適応する際に以下の手順を踏む必要がありました。

  1. 一時的なレンダーテクスチャを取得
  2. 元のテクスチャから一時的なレンダーテクスチャにポストエフェクトを適応して描画
  3. 一時的なレンダーテクスチャから元のテクスチャに描画
  4. 一時的なレンダーテクスチャの解放

URP12からはScriptableRenderPass.Blitメソッドを使用することで、一時的なレンダーテクスチャを用意せずとも、カラーバッファにポストエフェクトを適応させることができるようになりました。

今回のコード上の箇所ですと、以下になります。

var cmd = CommandBufferPool.Get(ProfilerTag);
// Blit1回で良くなった
Blit(cmd, ref renderingData, material);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);

以前との比較

右がURP10でのポストエフェクト、左がUPR12でのSwapBufferを用いたポストエフェクトになります。
コード量の差が一目瞭然かと思います。

描画結果

参考サイト様

light11.hatenadiary.com

youtu.be