Unity动态高斯模糊效果Shader

效果展示:

  • 可以根据具体值更改模糊程度

  • 也可以根据时间进行渐变模糊

如何使用?

  • 首先创建一个空物体,将SetMotionBlur脚本挂到空物体上

  • 新建一个Image,并适应Canvas,将TS_MotionBlur材质球挂上即可

实现代码:

  • Shader代码,用于实现高斯模糊效果

Shader "TS/MotionBlur"
{
    Properties
    {
        _Color("Main Color", Color) = (1,1,1,1)
        _Size("Size", Range(0, 20)) = 1
    }
        Category{

        // We must be transparent, so other objects are drawn before this one.  
        Tags {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
            "PreviewType" = "Plane"
            "CanUseSpriteAtlas" = "True"
        }


        SubShader {

                // Horizontal blur  
                GrabPass
                {
                    Tags { "LightMode" = "Always" }
                }
                Pass {
                    Tags { "LightMode" = "Always" }

                    Name "MotionBlur"
                    CGPROGRAM
                    #pragma vertex vert  
                    #pragma fragment frag  
                    #pragma fragmentoption ARB_precision_hint_fastest  
                    #include "UnityCG.cginc"  

                    struct appdata_t {
                        float4 vertex : POSITION;
                        float2 texcoord : TEXCOORD0;
                        float4 color    : COLOR;
                    };

                    struct v2f {
                        float4 vertex : POSITION;
                        float4 uvgrab : TEXCOORD0;
                        float4 color    : COLOR;
                    };

                    v2f vert(appdata_t v) {
                        v2f o;
                        o.vertex = UnityObjectToClipPos(v.vertex);
                        #if UNITY_UV_STARTS_AT_TOP  
                        float scale = -1.0;
                        #else  
                        float scale = 1.0;
                        #endif  
                        o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
                        o.uvgrab.zw = o.vertex.zw;

                        o.color = v.color;
                        return o;
                    }

                    sampler2D _GrabTexture;
                    float4 _GrabTexture_TexelSize;
                    float4 _MainTex_TexelSize;
                    float _Size;
                    uniform float4 _Color;

                    half4 GrabPixel(v2f i, float weight, float kernel) {
                        kernel = sign(sign(abs(i.uvgrab.x)) + sign(abs(i.uvgrab.y))) * kernel;
                        return tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernel * _Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight;
                    }
                    half4 frag(v2f i) : COLOR {
                        half4 sum = half4(0,0,0,0);
                        sum += GrabPixel(i, 0.05, -4.0);
                        sum += GrabPixel(i, 0.09, -3.0);
                        sum += GrabPixel(i, 0.12, -2.0);
                        sum += GrabPixel(i, 0.15, -1.0);
                        sum += GrabPixel(i, 0.18,  0.0);
                        sum += GrabPixel(i, 0.15, +1.0);
                        sum += GrabPixel(i, 0.12, +2.0);
                        sum += GrabPixel(i, 0.09, +3.0);
                        sum += GrabPixel(i, 0.05, +4.0);

                        float4 col5 = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
                        fixed decayFactor = sign(sign(abs(i.uvgrab.x)) + sign(abs(i.uvgrab.y)));
                        sum = lerp(col5, sum, decayFactor) * i.color * _Color;

                        return sum;
                    }
                    ENDCG
                }

         
        GrabPass {
            Tags { "LightMode" = "Always" }
        }
        Pass {
            Tags { "LightMode" = "Always" }

            Name "MotionBlur"
            CGPROGRAM
            #pragma vertex vert  
            #pragma fragment frag  
            #pragma fragmentoption ARB_precision_hint_fastest  
            #include "UnityCG.cginc"  

            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord: TEXCOORD0;
                float4 color    : COLOR;
            };

            struct v2f {
                float4 vertex : POSITION;
                float4 uvgrab : TEXCOORD0;
                float4 color    : COLOR;
            };

            v2f vert(appdata_t v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                #if UNITY_UV_STARTS_AT_TOP  
                float scale = -1.0;
                #else  
                float scale = 1.0;
                #endif  
                o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
                o.uvgrab.zw = o.vertex.zw;

                o.color = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;
            float _Size;
            uniform float4 _Color;

            half4 GrabPixel(v2f i, float weight, float kernel) {
                kernel = sign(sign(abs(i.uvgrab.x)) + sign(abs(i.uvgrab.y))) * kernel;
                return tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y * kernel * _Size, i.uvgrab.z, i.uvgrab.w))) * weight;
            }

            half4 frag(v2f i) : COLOR
            {
                half4 sum = half4(0,0,0,0);
                sum += GrabPixel(i, 0.05, -4.0);
                sum += GrabPixel(i, 0.09, -3.0);
                sum += GrabPixel(i, 0.12, -2.0);
                sum += GrabPixel(i, 0.15, -1.0);
                sum += GrabPixel(i, 0.18,  0.0);
                sum += GrabPixel(i, 0.15, +1.0);
                sum += GrabPixel(i, 0.12, +2.0);
                sum += GrabPixel(i, 0.09, +3.0);
                sum += GrabPixel(i, 0.05, +4.0);

                float4 col5 = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
                fixed decayFactor = sign(sign(abs(i.uvgrab.x)) + sign(abs(i.uvgrab.y)));
                sum = lerp(col5, sum, decayFactor) * i.color * _Color;

                return sum;
            }
            ENDCG
        }
    }
    }
}

C#代码,用于Demo演示及如何调用Shader里的_size值

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

public class SetMotionBlur : MonoBehaviour
{
    public Material motionBlurMaterial; // 引用具有MotionBlur Shader的材质
    float value = 0;
    public bool isUpdate = false;
    void Start()
    {
        // 检查材质和Shader是否正确设置
        if (motionBlurMaterial != null && motionBlurMaterial.shader.name == "TS/MotionBlur")
        {
            // 设置初始的Size值
            motionBlurMaterial.SetFloat("_Size", 1.0f);
        }
        else
        {
            Debug.LogError("MotionBlur材质或Shader未正确设置。");
        }
    }
    void Update()
    {


        if (isUpdate)
        {
            //来回执行 增强 减弱 
            float newSize = Mathf.PingPong(Time.time * 15, 20.0f);
            motionBlurMaterial.SetFloat("_Size", newSize);
        }
        else
        {
            if (Input.GetKeyDown(KeyCode.Q))
            {
                //判断是否超出范围
                if (value + 5 <= 20)
                {
                    value += 5;
                    motionBlurMaterial.SetFloat("_Size", value);
                    Debug.Log(string.Format("<color=yellow>{0}</color>", "模糊已增强"));
                }
                else
                {
                    Debug.LogError("超出范围,请先减弱模糊");
                }

            }
            if (Input.GetKeyDown(KeyCode.E))
            {
                //判断是否超出范围
                if (value - 5 >= 0)
                {
                    value -= 5;
                    motionBlurMaterial.SetFloat("_Size", value);
                    Debug.Log(string.Format("<color=cyan>{0}</color>", "模糊已减弱"));
                }
                else
                {
                    Debug.LogError("超出范围,请先增强模糊");
                }

            }
        }
    }
    /// <summary>
    /// 
    /// </summary>
    void OnGUI()
    {
        GUIStyle fontStyle = new GUIStyle();
        fontStyle.alignment = TextAnchor.UpperLeft;
        fontStyle.fontSize = 60;
        fontStyle.fontStyle = FontStyle.Bold;
        fontStyle.normal.textColor = new Color(50 / 255f, 50 / 255f, 50 / 255f, 1);
        if (isUpdate==false)
        {
            GUI.Label(new Rect(20, 20, 60, 60), "Q键增强模糊效果 E键减弱模糊效果", fontStyle);
            GUI.Label(new Rect(20, 100, 60, 60), "勾选isUpdate执行限值内自运行", fontStyle);
        }
    }
    /// <summary>
    /// 编辑器模式
    /// </summary>
    public void OnValidate()
    {
        if (isUpdate)
        {
            Debug.Log(string.Format("<color=red>{0}</color>", "开始执行限值内自运行"));
        }
        else
        {
            Debug.Log(string.Format("<color=red>{0}</color>", "停止执行限值内自运行"));
        }
    }
}

最后附上实例Demo包

点击下载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值