🦁

Unity6における汎用ポストエフェクトパス

に公開

はじめに

前回のMRTに続きUnity6実装紹介第二弾です。
今回はシンプルで汎用的なポストエフェクトパスを作成しました。

RendererFeature

RendererFeatureは前と変わらないのでサクッとコードだけ乗せます。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class PostEffectRendererFeature : ScriptableRendererFeature
{
    [SerializeField]
    private List<Material> _material;
    private PostEffectRenderPass _postEffectRenderPass;
    
    public override void Create()
    {
        _postEffectRenderPass  = new PostEffectRenderPass(_material);
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(_postEffectRenderPass);
    }
}

RendererPass

まずはBlitの描画先のテクスチャを用意します。

var resourceData = frameData.Get<UniversalResourceData>();
var activeColorTexture = resourceData.activeColorTexture;
TextureDesc desc = renderGraph.GetTextureDesc(activeColorTexture);
desc.name = "TempTexture";
TextureHandle tempTexture = renderGraph.CreateTexture(desc);

次にBlitします。
RenderGraphでBlitする際はRenderGraph.AddBlitPassを使用します。

RenderGraphUtils.BlitMaterialParameters param = new(activeColorTexture, tempTexture, material, 0);
renderGraph.AddBlitPass(param);

最後にtempTextureの結果をカメラテクスチャに戻します。
戻す際はBlitまでする必要がないのでRenderGraph.AddCopyPassを使用します。

renderGraph.AddCopyPass(tempTexture, activeColorTexture);

これで一回分のポストエフェクトを描画することが出来るようになりました。

複数回ポストエフェクトを描画する

今回は汎用パスということでポストエフェクトを新しく作るたびにパスを作らないように複数のポストエフェクトを描画できるようにします。
仕組みは簡単で奇数回の場合はtempTextureに描画し、偶数回の場合はカメラテクスチャに描画します。
そうすることによりテクスチャの節約ができます。
また最後が奇数階の場合はAddCopyPassでカメラテクスチャに結果を描画します。
以下が実装になります。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;

public class PostEffectRenderPass : ScriptableRenderPass
{
    private readonly List<Material> _material;

    public PostEffectRenderPass(List<Material> material, RenderPassEvent renderPassEvent =  RenderPassEvent.BeforeRenderingPostProcessing)
    {
        _material = material;
        this.renderPassEvent = renderPassEvent;
    }
    
    public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
    {
        var resourceData = frameData.Get<UniversalResourceData>();
        var activeColorTexture = resourceData.activeColorTexture;
        TextureDesc desc = renderGraph.GetTextureDesc(activeColorTexture);
        desc.name = "PostEffectTempTexture";
        TextureHandle tempTexture = renderGraph.CreateTexture(desc);

        int loop;
        for (loop = 0; loop < _material.Count; loop++)
        {
            if (loop % 2 == 0)
            {
                RenderGraphUtils.BlitMaterialParameters param = new(activeColorTexture, tempTexture, _material[loop], 0);
                renderGraph.AddBlitPass(param);
            }
            else
            {
                RenderGraphUtils.BlitMaterialParameters param = new(tempTexture, activeColorTexture, _material[loop], 0);
                renderGraph.AddBlitPass(param);
            }

        }

        // 奇数ならコピーする
        if (loop % 2 == 1)
        {
            renderGraph.AddCopyPass(tempTexture, activeColorTexture);
        }

    }
}

以上が実装になります。
使い方はポストエフェクトのマテリアルをRendererFeatureにセットするだけです。

こんな感じで色収差とヴィネットがちゃんと出ました。

Discussion