【Unity】【シェーダ】ディレクショナルブラーのポストエフェクト実装する

Unityのシェーダでディレクショナルブラーのポストエフェクト実装する方法です。

Unity2019.2.18

はじめに

この記事ではUnityのシェーダでディレクショナルブラーをかけるポストエフェクトを実装する方法をまとめます。
Unityでポストエフェクトを掛ける基本的な方法については以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

シェーダ

早速ですが、まずシェーダ全文を掲載します。

Shader "Example"
{
    Properties
    {
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
        _SampleCount ("Sample Count", int) = 5
        _HorizontalIntensity ("Horizontal Intensity", Range(0.0, 1.0)) = 0.5
        _BlurIntensity ("Blur Intensity", Range(0.0, 1.0)) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        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;
            int _SampleCount;
            float _HorizontalIntensity;
            float _BlurIntensity;

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

            fixed4 frag (v2f i) : SV_Target
            {
                float2 offset = float2(_HorizontalIntensity, 1.0 - _HorizontalIntensity) * _BlurIntensity / _SampleCount;

                half3 rgb = 0;
                for (int j = 0; j < _SampleCount; j++)
                {
                    half sign = (j % 2 * 2 - 1); // ループごとに交互に1と-1を取る符号
                    float2 uv = i.uv + offset * j * sign;
                    rgb += tex2D(_MainTex, uv).rgb;
                }
                rgb /= _SampleCount;
                return fixed4(rgb, 1);
            }
            ENDCG
        }
    }
}

実装はシンプルです。

まずブラーを掛けたい方向にUVをずらしてテクスチャをサンプリングします。
次にこれと反対方向にもう少し大きめにUVをずらしてサンプリングします。
つぎにまた反対方向に..とこれを交互に繰り返すことでブラーを作っています。

レンダリング結果

さてこれをポストエフェクトとしてレンダリングします。
ポストエフェクトを掛けるためのスクリプトは以下のように書きます。

using UnityEngine;

public class Example : MonoBehaviour
{
    [SerializeField]
    private Material _material;
    [SerializeField, Range(1, 20)]
    private int _sampleCount = 5;
    [SerializeField, Range(0.0f, 1.0f)]
    private float _horizontalIntensity = 0.5f;
    [SerializeField, Range(0.0f, 1.0f)]
    private float _blurIntensity = 0.5f;

    private void OnRenderImage(RenderTexture source, RenderTexture dest)
    {
        _material.SetFloat("_SampleCount", _sampleCount);
        _material.SetFloat("_HorizontalIntensity", _horizontalIntensity);
        _material.SetFloat("_BlurIntensity", _blurIntensity);
        Graphics.Blit(source, dest, _material);
    }
}

これをカメラにアタッチして実行すると以下の結果が得られます。

f:id:halya_11:20191206014933p:plain
効果なし

f:id:halya_11:20191206015008p:plain
Horizontal Intensity : 0.5
Blur Intensity : 0.04

f:id:halya_11:20191206015049p:plain
Horizontal Intensity : 0.5
Blur Intensity : 0.1

関連

light11.hatenadiary.com