rn.log

備忘録など

【Unity2020.2】URP向けのグレースケールPostEffectを作る

はじめに

Unity 2020.2 の Universal RP 向けのグレースケールポストエフェクトを作ってみました。

f:id:r-ngtm:20201219214342j:plain:w480
グレースケールをかける前
f:id:r-ngtm:20201219214403j:plain:w480
グレースケールをかけた後

環境

Unity 2020.2
Universal RP 10.2.2

ポストエフェクトに必要なもの

Universal RP でポストエフェクトを実装する際、以下のようなデータを扱うことになります。
・Universal Render Pipeline Asset
・Forward Renderer Data
・ポストエフェクト用シェーダー (.shader)
・RendererFeature (C#スクリプト)

ポストエフェクト実装の流れ

1. ポストエフェクト用シェーダー (.shader)を作る
2. ポストエフェクトを実行するRendererFeatureを作る
3. ForwardRendererDataを作成し、RendererFeatureをそこへ登録する
4. Universal Render Pipeline アセットにForwardRendererDataを登録
5. シーンのCameraコンポーネントから、使用したいForwardRendererDataを選択
6. 画面にグレースケールがかかるようになる

イメージとしては以下のようになります。

f:id:r-ngtm:20201219221843p:plain:w640
Forward
f:id:r-ngtm:20201219222456p:plain:w640
グレイスケールを実装したRendererFeature

グレースケールエフェクトを作ってみる

1 : ポストエフェクト用シェーダー

画面色のR, G, B からグレースケールを計算するシェーダーを作成します。

今回は CIE XYZ を利用してグレースケールを計算しました。

Gray = 0.2126 * R + 0.7152 * G + 0.0722 * B

参考 : グレースケール画像のうんちく - Qiita

以下のシェーダーを Grayscale.shader としてUnityプロジェクト内に保存します。

Shader "PostEffect/Grayscale"
{
    Properties
    {
        [HideInInspector] _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return dot(col.rgb, fixed3(0.2126, 0.7152, 0.0722));
            }
            ENDCG
        }
    }
}

2 : RendererFeature

次に、カメラのレンダリング結果にグレースケールを適用するRendererFeatureを実装します。
以下のスクリプトGrayscale.cs としてUnityプロジェクト内に保存します。

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

public class Grayscale : ScriptableRendererFeature
{
    [System.Serializable]
    public class GrayscaleSetting
    {
        // レンダリングの実行タイミング
        public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
    }

    /// <summary>
    /// Grayscale実行Pass
    /// </summary>
    class GrayScalePass : ScriptableRenderPass
    {
        private readonly string profilerTag = "GrayScale Pass";

        public Material grayscaleMaterial; // グレースケール計算用マテリアル

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            var cameraColorTarget = renderingData.cameraData.renderer.cameraColorTarget;

            // コマンドバッファ
            var cmd = CommandBufferPool.Get(profilerTag);

            // マテリアル実行
            cmd.Blit(cameraColorTarget, cameraColorTarget, grayscaleMaterial);

            context.ExecuteCommandBuffer(cmd);
        }
    }

    [SerializeField] private GrayscaleSetting settings = new GrayscaleSetting();
    private GrayScalePass scriptablePass;

    public override void Create()
    {
        var shader = Shader.Find("PostEffect/Grayscale");
        if (shader)
        {
            scriptablePass = new GrayScalePass();
            scriptablePass.grayscaleMaterial = new Material(shader);
            scriptablePass.renderPassEvent = settings.renderPassEvent;
        }
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (scriptablePass != null && scriptablePass.grayscaleMaterial != null)
        {
            renderer.EnqueuePass(scriptablePass);
        }
    }
}

3 : Forward Renderer Data の作成

Forward Renderer Data を作成します。

f:id:r-ngtm:20201219215943p:plain

Forward Renderer Data は以下のような名前にしてみました。

f:id:r-ngtm:20201219220111p:plain
作成した Forward Renderer Data

4 : Forward Renderer Data を PIpeline Asset へ登録

Univesal Render Pipeline Asset へ STEP1で作成したForward Renderer Data を登録します。

f:id:r-ngtm:20201219220209p:plain
Forward Renderer Data を Pipeline Assetへ登録

5 : Forward Renderer Data に Grayscale を登録

Forward Renderer Data に Grayscale を登録します。

Add Renderer Feature ボタンをクリックします。

f:id:r-ngtm:20201219220520p:plain
Add Renderer Feature ボタンをクリックして、Renderer Feature を登録

ドロップダウンメニューからGrayscale を選択します。

f:id:r-ngtm:20201219220626p:plain
Grayscale RendererFeatureを選択
f:id:r-ngtm:20201219220726p:plain
登録された Grayscale

6 : カメラの設定

CameraコンポーネントのRenderer にて、 STEP2で PIpeline Asset に登録したForward Renderer Data を 選択します。

f:id:r-ngtm:20201219220828p:plain
CameraコンポーネントのRenderer の設定
f:id:r-ngtm:20201219220209p:plain
STEP2 で 登録したForward Renderer Data

結果

画面にグレースケールエフェクトが適用されます。

f:id:r-ngtm:20201219214403j:plain
画面にグレースケールエフェクトが適用される