Unity Shader PostProcessing - 9 - RadialBlur 径向模糊

141 篇文章 32 订阅


径向模糊这个概念最初我是在高中的时候学习PS有介绍的。
当时就觉得这个效果很棒。

当然PS那个径向模糊比我实现的这个效果要好(我这个也不能实现太好的效果,运行在手机上会受不了),毕竟PS是离线编辑,且针对一帧图像处理的,不存在什么性能不性能的问题,怎么炫就怎么来。

实现

从PS上的径向模糊不难理解,就是对指定某个径向点后,如下图中的绿色点C是径向点,红色的P,Q两点别分与C点直线上的前前后后都用采样点,就那些蓝色点,越是靠近C点,采样距离越小,所以模糊程度响度来说会比较小的(意思就会相对边缘的来说会比较清晰)。
在这里插入图片描述
来看看运行中,我们将其他参数调整一下,只看采样距离
在这里插入图片描述

注意查看远处的三颗球,红色圆圈是球的原始位置,黄色箭头是前前后后分别采样的位置,越靠近径向点,采样距离就越近。

还看不出来的话,你就直接看人物的头部,中间部分是最清晰的。

控制采样步长

在代码上只要控制好采样步长就可以了:

float2 stepDir = normalize(vec) * _SampleDistance; // 每次的采样步长方向
float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小
stepDir *= stepLenFactor; // 控制步长值,stepLenFactor=len * 0.1 * _Intensity中的:0.1是经验数值可以不管,或是外部公开控制也是可以的
fixed4 sum = 0;
for (int it = 0; it < sampleCount; it++) {
    float2 appliedStep = stepDir * it;
    sum += tex2D(_DownSampleRT, i.uv + appliedStep); // 正向采样
    sum += tex2D(_DownSampleRT, i.uv - appliedStep); // 反向采样
}

主要看这么一句:

float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小

就可以控制越径向点月经采样距离越小

完整代码如下:

完整的Shader

// jave.lin 2020.03.21 径向模糊 - Radial Blur
Shader "Custom/RadialBlur" {
    CGINCLUDE
    #include "UnityCG.cginc"
    struct appdata {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
    };
    float _Intensity;           // 径向效果的强度
    float _FadeRadius;          // 淡出径向效果的半径范围
    float _SampleDistance;      // 每次采样的距离
    sampler2D _DownSampleRT;    // 原图降采样后的图
    sampler2D _SrcTex;          // 原始图像纹理
    v2f vert(appdata v) {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }
    fixed4 frag(v2f i) : SV_Target {
        const int sampleCount = 5; // 单想采样次数,乘以2就是真的总次数
        const float invSampleCount = 1.0 / ((float)sampleCount * 2);
        float2 vec = i.uv - 0.5;
        float len = length(vec);
        float fade = smoothstep(0, _FadeRadius, len); // 平滑淡出的径向效果值
        float2 stepDir = normalize(vec) * _SampleDistance; // 每次的采样步长方向
        float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小
        stepDir *= stepLenFactor; // 控制步长值,stepLenFactor=len * 0.1 * _Intensity中的:0.1是经验数值可以不管,或是外部公开控制也是可以的
        fixed4 sum = 0;
        for (int it = 0; it < sampleCount; it++) {
            float2 appliedStep = stepDir * it;
            sum += tex2D(_DownSampleRT, i.uv + appliedStep); // 正向采样
            sum += tex2D(_DownSampleRT, i.uv - appliedStep); // 反向采样
        }
        sum *= invSampleCount; // 均值模糊
        return lerp(tex2D(_SrcTex, i.uv), sum, fade * _Intensity);
    }
    ENDCG
    SubShader {
        Cull Off ZWrite Off ZTest Always
        Pass {
            NAME "RADIA_BLUR"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}

均值模糊

完整的Shader中,也可以看到,我也采样的是均值模糊sum *= invSampleCount; // 均值模糊,性能上也是比较高的方式。

DownSample

接下来我们再对采样图做了downSample(就是对径向模糊的数据源采样图做了降低分辨率),最后就只有58 x 27左右的尺寸,在移动端上性能是很可观的,而且降低采样图尺寸后除了占用VRAM(显存)少了,就连模糊的效果也提升了,实在是一举两得。
在这里插入图片描述
在这里插入图片描述

完整的CSharp

using UnityEngine;
/// <summary>
/// jave.lin 2020.03.21 径向模糊 Radial Blur
/// </summary>
public class RadialBlurScript : MonoBehaviour
{
    private static int _Intensity_hash = Shader.PropertyToID("_Intensity");
    private static int _FadeRadius_hash = Shader.PropertyToID("_FadeRadius");
    private static int _SampleDistance_hash = Shader.PropertyToID("_SampleDistance");
    private static int _SrcTex_hash = Shader.PropertyToID("_SrcTex");
    private static int _DownSampleRT_hash = Shader.PropertyToID("_DownSampleRT");

    public Material mat;

    [Header("Radial Blur")]
    [Range(0, 1)]
    public float intensity = 1;                         // 效果强度
    [Range(0f, 1f)]
    public float fadeRadius = 0.38f;                    // 半径范围内的都淡出
    [Range(0f, 1f)]
    public float sampleDistance = 0.25f;                // 径向模糊每次采样的距离
    [Range(1, 40)]
    public int blurDownSample = 40;                     // 模糊降低输出采样率
    private Camera cam;
    private void Start()
    {
        cam = GetComponent<Camera>();
        cam.depthTextureMode |= DepthTextureMode.Depth;
    }
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (!mat)
        {
            Graphics.Blit(source, destination);
            return;
        }
        var rw = Screen.width / blurDownSample;
        var rh = Screen.height / blurDownSample;
        RenderTexture downSampleRT = RenderTexture.GetTemporary(rw, rh, 0);
        downSampleRT.filterMode = FilterMode.Bilinear;
        downSampleRT.name = "downSampleRT";
        Graphics.Blit(source, downSampleRT);
        mat.SetFloat(_Intensity_hash, intensity);
        mat.SetFloat(_FadeRadius_hash, fadeRadius);
        mat.SetFloat(_SampleDistance_hash, sampleDistance);
        mat.SetTexture(_DownSampleRT_hash, downSampleRT);
        mat.SetTexture(_SrcTex_hash, source);
        Graphics.Blit(null, destination, mat, 0);
        RenderTexture.ReleaseTemporary(downSampleRT);
    }
}

运行效果

在这里插入图片描述
在这里插入图片描述

Project

backup : UnityShader_RadialBlurTesting_2018.3.0f2

Referneces

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值