【Unity】【HDRP】Radial Blur(放射状ブラー)のポストエフェクトを実装する

UnityのHDRPでRadial Blur(放射状ブラー)のポストエフェクトを実装する方法についてまとめました。

Unity2020.3.22f1
High Definition RP 10.7.0

はじめに

本記事ではUnityのHDRPでRadial Blur(放射状ブラー)のポストエフェクトを実装する方法についてまとめます。

f:id:halya_11:20211209180652g:plain
Radial Blur

Radial Blurポストエフェクトの基礎知識については省略しますので、以下の記事を参照してください。

light11.hatenadiary.com

また、HDRPのカスタムポストエフェクトに関する基礎知識は以下の記事を参照してください。

light11.hatenadiary.com

シェーダを作成する

それではまずシェーダを作成します。

Shader "Hidden/Shader/RadialBlur"
{
    HLSLINCLUDE

    #pragma target 4.5
    #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch

    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"

    struct Attributes
    {
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct Varyings
    {
        float4 positionCS : SV_POSITION;
        float2 texcoord   : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    };

    Varyings Vert(Attributes input)
    {
        Varyings output;
        UNITY_SETUP_INSTANCE_ID(input);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
        output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
        output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
        return output;
    }

    float _Intensity;
    float _SampleCount;
    TEXTURE2D_X(_InputTexture);

    float4 CustomPostProcess(Varyings input) : SV_Target
    {
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

        half3 col = 0;
        half2 symmetryUv = input.texcoord - 0.5;
        half distance = length(symmetryUv);
        half factor = _Intensity / _SampleCount * distance;
        for(int i = 0; i < _SampleCount; i++) {
            half uvOffset = 1 - factor * i;
            half2 uv = symmetryUv * uvOffset + 0.5;
            uint2 positionSS = uv * _ScreenSize.xy;
            col += LOAD_TEXTURE2D_X(_InputTexture, positionSS).rgb;
        }
        col /= _SampleCount;
        
        return float4(col, 1);
    }

    ENDHLSL

    SubShader
    {
        Pass
        {
            Name "RadialBlur"

            ZWrite Off
            ZTest Always
            Blend Off
            Cull Off

            HLSLPROGRAM
                #pragma fragment CustomPostProcess
                #pragma vertex Vert
            ENDHLSL
        }
    }
    Fallback Off
}

HDRPの書き方に合わせて変えてますが処理自体は以下の記事と同じです。

light11.hatenadiary.com

Volumeスクリプトを作成する

次にVolumeスクリプトを作成します。

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;

[Serializable]
[VolumeComponentMenu("Post-processing/Custom/RadialBlur")]
public sealed class RadialBlur : CustomPostProcessVolumeComponent, IPostProcessComponent
{
    private const string ShaderName = "Hidden/Shader/RadialBlur";

    private static readonly int Intensity = Shader.PropertyToID("_Intensity");
    private static readonly int SampleCount = Shader.PropertyToID("_SampleCount");
    private static readonly int InputTexture = Shader.PropertyToID("_InputTexture");

    public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
    public ClampedIntParameter sampleCount = new ClampedIntParameter(8, 4, 16);

    private Material _material;

    public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;

    public bool IsActive()
    {
        return _material != null && intensity.value > 0f;
    }

    public override void Setup()
    {
        if (Shader.Find(ShaderName) != null)
        {
            _material = new Material(Shader.Find(ShaderName));
        }
        else
        {
            Debug.LogError($"Unable to find shader '{ShaderName}'. Post Process Volume RadialBlur is unable to load.");
        }
    }

    public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
    {
        if (_material == null)
        {
            return;
        }

        _material.SetFloat(Intensity, intensity.value);
        _material.SetFloat(SampleCount, sampleCount.value);
        _material.SetTexture(InputTexture, source);
        HDUtils.DrawFullScreen(cmd, _material, destination);
    }

    public override void Cleanup()
    {
        CoreUtils.Destroy(_material);
    }
}

こちらも特に難しいことはやっていません。

シーンに適用する

あとはこれを以下の記事のようにしてシーンに適用するだけです。

light11.hatenadiary.com

適用した結果は以下の通りとなりました。

f:id:halya_11:20211209193814p:plain
結果

アニメーションさせるとこんな感じです。

f:id:halya_11:20211209180652g:plain
結果

正常にRadial Blurが掛かっていることが確認できました。

関連

light11.hatenadiary.com

light11.hatenadiary.com