Unity 径向模糊 简易解决方案


本文欢迎转载,转载请标明出处!

什么是径向模糊

径向模糊,这个名字咋一看很陌生,不知道是什么东西,但是看了下面这对对比图也许你就知道是什么了。

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

(PID:77789607)

可见图2中出现了一个由定点扩散型的模糊,这个就是径向模糊。

径向模糊的运用非常广泛。由于这种扩散型的模糊可以带来很强的速度感和压迫感,常用于竞速游戏或者高速移动的对象上,也有用于Boss的登场画面特效等等。

一、原理分析和算法简介

既然是一个定点扩散型的模糊,那就需要有一个扩散的起点。在我们的Shader渲染过程中,这个起点可以用UV坐标属性来确定。

其次就是这个扩散的效果,先贴上核心的算法:
在这里插入图片描述
(来源:https://qianmo.blog.youkuaiyun.com/article/details/105350519)

  • 首先是我们需要计算出模糊的方向Offset,后面要用这个Offset值偏移UV持续采样。这个通过扩散定点的坐标减去当前像素的UV坐标就可以得出。得到方向后,通过一个额外的参数来控制这个方向带来的扩散效果
  • 既然是模糊,那就避免不了多次采样。径向模糊需要多次采样来保证模糊效果,并在每次采样后,采样坐标继续与扩散方向进行累加,并累加采样后的颜色。最终,输出这几次采样颜色的平均值。整体来看,径向模糊的主要逻辑相对于高斯模糊要简单不少,而且可以在一个Pass中就处理完毕。
  • 核心代码中的unroll关键字的意义在于告诉着色器可以安全展开多少次遍历。这样一来,在Shader编译成OpenGL或者其他着色器语言的时候会把这个循环展开,最终效果就等同于我们把10,11行所在的代码重复写30次。

二、具体实现

新建一个项目,保存场景,创建一个Canvas,并修改Canvas的RenderMode为ScreenSpace-Camer。笔者这里图个方便,就挂主摄像机上去了。在实际项目中,一定要严格区分场景和UI摄像机

在这里插入图片描述
创建一个RawImage,放上一张图片。

在这里插入图片描述
新建一个Shader,命名为RadiusBlur,Shader的代码如下:

Shader "SaberShad/RadiusBlur"
{
   
    Properties
    {
   
        [HideInInspector]_MainTex ("Texture", 2D) = "white" {
   }
        // 径向模糊数据 xy分量代表径向中心点  z分量代表偏移 
        _RadiusData("Radius Data", Vector) = (0.5, 0.5, 0.0, 1.0)
        _RadiusIteration("Radius Iteration", Range(1, 30)) = 1.0
    }
    SubShader
    {
   
        CGINCLUDE
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            half3 _RadiusData;
            half _RadiusIteration;

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

            struct v2f_rb
            {
   
                float4 vertex : SV_POSITION;
                float2 texcoord: TEXCOORD0;
            };

            v2f_rb RadiusBlurVertex(a2f_rb v)
            {
   
                v2f_rb o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texcoord = TRANSFORM_TEX(v.uv, _MainTex);

                return o;
            }

            half4 RadiusBlurFragment(v2f_rb i): SV_Target
            {
   
                half2 radiusRange = (_RadiusData.xy - i.texcoord.xy) * _RadiusData.z;

                half4 color = 0.0;
                [unroll(30)]
                for(int j = 0; j < _RadiusIteration; j++)
                {
   
                    color += tex2D(_MainTex, i.texcoord);
                    i.texcoord += radiusRange;
                }

                return color / _RadiusIteration;
            }
        ENDCG

        Cull Off ZWrite Off ZTest Always
		Pass
		{
   
			CGPROGRAM
			#pragma vertex RadiusBlurVertex
			#pragma fragment RadiusBlurFragment
			ENDCG
		}
    }
}

参数方面,把中心点坐标和偏移强度参数整合到了一个Vector4参数中来传递。

新建一个材质球RadiusMat,把材质球的shader改成我们刚刚处理的Shader。

在这里插入图片描述
接着是写一个摄像机可以用的后处理类RadiusBlur,这个类的作用在于控制摄像机的渲染输出前处理我们的模糊效果,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class RadiusBlur : MonoBehaviour
{
   
    [SerializeField]
    public Material radius_material;

    [SerializeField]
    public Vector3 radius_data{
   
        get{
   
            if(radius_material != null)
            {
   
                return radius_material.GetVector("_RadiusData");
            }
            return new Vector3(0.5f, 0.5f, 0.01f);
        }
        set{
   
            if(radius_material != null)
            {
   
                radius_material.SetVector("_RadiusData", value);
            }
        }
    }

    [SerializeField]
    public int iteration{
   
        
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值