美文网首页
模糊shader总结(均值模糊,高斯模糊)

模糊shader总结(均值模糊,高斯模糊)

作者: 星易乾川 | 来源:发表于2020-12-02 22:29 被阅读0次
image.png
效果排序 高斯+降采样>高斯>均值
CommandBuff的实现效果好,效率可控,但缺点是无法用在UI上
UI上用模糊好像只能是GrabPass,其他方法暂时没想到
参考了一些文章,下面是连接,在他们基础上做了些修改,仅作为个人学习使用
高斯模糊:
https://blog.csdn.net/pz789as/article/details/79050631
https://blog.csdn.net/puppet_master/article/details/52783179
http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
基于CommandBuff的高斯模糊:
https://www.gameres.com/844940.html
均值模糊:
https://blog.csdn.net/puppet_master/article/details/52547442
https://zhuanlan.zhihu.com/p/145463708

_MainTexture_TexelSize
{TextureName}_TexelSize - a float4 property contains texture size information:

  • x contains 1.0/width
  • y contains 1.0/height
  • z contains width
  • w contains height

均值模糊代码:

Shader "UI/BlurUI_SimpleBlur"
{
    Properties
    {
        _Color("Color", COLOR) = (1,1,1,1)
        _Radius("Blur Radius", Range(0, 4)) = 1
        _Size("Blur Size", Range(0, 5)) = 1
    }

        SubShader
    {
        Tags{ "Queue" = "Transparent"}

        //GrabPass {}

    GrabPass{}
        Pass
        {
        //Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

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

        struct v2f
        {
            float4 vertex : SV_POSITION;
            float4 screenPos : TEXCOORD0;
            float4 grabPos : TEXCOORD1;
        };

        sampler2D _GrabTexture;
        float4 _GrabTexture_TexelSize;

        float4 _Color;
        int _Radius;
        float _Size;
        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.screenPos = ComputeScreenPos(o.vertex);
            o.grabPos = ComputeGrabScreenPos(o.vertex);
            return o;
        }

        half4 frag(v2f i) : SV_TARGET
        {

            float4 result = tex2Dproj(_GrabTexture, i.screenPos);
            i.grabPos.zw = i.screenPos.zw;
            for (int range = 1; range <= _Radius; range++)
            {
                //对
                float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * range * _Size);
                i.grabPos.xy = w1;
                result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);//用屏幕坐标+偏移,这里没搞懂,但是实测效果确实好

                float2 w2 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * -range * _Size);
                i.grabPos.xy = w2;
                result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
            }

            result /= _Radius * 2 + 1;      //除以_Radius*2取均值

            return result;
        }
        ENDCG
    }

        GrabPass{}
        Pass
        {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 screenPos : TEXCOORD0;
                float4 grabPos : TEXCOORD1;
            };

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;

            float4 _Color;
            int _Radius;
            float _Size;
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.screenPos = ComputeScreenPos(o.vertex);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                return o;
            }

            half4 frag(v2f i) : SV_TARGET
            {

                float4 result = tex2Dproj(_GrabTexture, i.screenPos);
                i.grabPos.zw = i.screenPos.zw;
                for (int range = 1; range <= _Radius; range++)
                {
                    float2 w3 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * range * _Size, _GrabTexture_TexelSize.y * 0);
                    i.grabPos.xy = w3;
                    result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);

                    float2 w4 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * -range * _Size, _GrabTexture_TexelSize.y * 0);
                    i.grabPos.xy = w4;
                    result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);

                }

                result /= _Radius * 2 + 1;
                float4 col = half4(_Color.a * _Color.rgb + (1 - _Color.a) * result.rgb, 1.0f);
                return col;
            }
            ENDCG

        }
    }

}

高斯模糊代码:

Shader "UI/BlurUI_GaussianBlur"
{
    Properties
    {
        _Color("Color", COLOR) = (1,1,1,1)
        //_Radius("Blur Radius", Range(0, 4)) = 1
        _Size("Blur Size", Range(0, 5)) = 1
    }

        SubShader
    {
        Tags{ "Queue" = "Transparent"}

        //GrabPass {}

    GrabPass{}
        Pass
        {
        //Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

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

        struct v2f
        {
            float4 vertex : SV_POSITION;
            float4 screenPos : TEXCOORD0;
            float4 grabPos : TEXCOORD1;
        };

        sampler2D _GrabTexture;
        float4 _GrabTexture_TexelSize;

        float4 _Color;
        int _Radius;
        float _Size;
        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.screenPos = ComputeScreenPos(o.vertex);
            o.grabPos = ComputeGrabScreenPos(o.vertex);
            return o;
        }
        half4 GrabPixel(v2f i, float weight, float kernelx)
        {
            //float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * kernelx * _Size);
            //i.grabPos.xy = w1;
   //         return tex2Dproj(_GrabTexture, i.screenPos + i.grabPos) * weight;        
            return tex2Dproj(_GrabTexture, i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x + _GrabTexture_TexelSize.x*kernelx*_Size, i.grabPos.y, i.grabPos.z, i.grabPos.w))) * weight;
        }

        half4 frag(v2f i) : SV_TARGET
        {

            //float4 result = tex2Dproj(_GrabTexture, i.screenPos/*UNITY_PROJ_COORD(i.grabPos)*/);
            //i.grabPos.zw = i.screenPos.zw;
            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);
            //for (int range = 1; range <= _Radius; range++)
            //{
            //  //对
            //  float2 w1 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * range * _Size);
            //  i.grabPos.xy = w1;
            //  result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);

            //  float2 w2 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * 0, _GrabTexture_TexelSize.y * -range * _Size);
            //  i.grabPos.xy = w2;
            //  result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);
            //}

            //result /= _Radius * 2 + 1;        //除以_Radius*2取均值

            return sum;
        }
        ENDCG
    }

        GrabPass{}
        Pass
        {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 screenPos : TEXCOORD0;
                float4 grabPos : TEXCOORD1;
            };

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;

            float4 _Color;
            int _Radius;
            float _Size;
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.screenPos = ComputeScreenPos(o.vertex);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                return o;
            }
            half4 GrabPixel(v2f i, float weight, float kernely)
        {
            //return tex2Dproj(_GrabTexture,i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x, i.grabPos.y + _GrabTexture_TexelSize.y*kernely*_Size, i.grabPos.z, i.grabPos.w))) * weight;        
            return tex2Dproj(_GrabTexture,i.screenPos + UNITY_PROJ_COORD(float4(i.grabPos.x, i.grabPos.y + _GrabTexture_TexelSize.y*kernely*_Size, i.grabPos.z, i.grabPos.w))) * weight;
        }
            half4 frag(v2f i) : SV_TARGET
            {

                //float4 result = tex2Dproj(_GrabTexture, i.screenPos/*UNITY_PROJ_COORD(i.grabPos)*/);
                //i.grabPos.zw = i.screenPos.zw;
                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);
                
                //for (int range = 1; range <= _Radius; range++)
                //{
                //  float2 w3 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * range * _Size, _GrabTexture_TexelSize.y * 0);
                //  i.grabPos.xy = w3;
                //  result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);

                //  float2 w4 = i.screenPos.xy + float2(_GrabTexture_TexelSize.x * -range * _Size, _GrabTexture_TexelSize.y * 0);
                //  i.grabPos.xy = w4;
                //  result += tex2Dproj(_GrabTexture, i.screenPos + i.grabPos);

                //}

                //result /= _Radius * 2 + 1;
                float4 col = half4(_Color.a * _Color.rgb + (1 - _Color.a) * sum.rgb, 1.0f);
                return col;
            }
            ENDCG

        }
    }

}

CommandBuff高斯模糊代码:
Shader
抓图做模糊用

Shader "Hidden/SeparableGlassBlur" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "" {}
    }

    CGINCLUDE
    
    #include "UnityCG.cginc"
    
    struct v2f {
        float4 pos : POSITION;
        float2 uv : TEXCOORD0;

        float4 uv01 : TEXCOORD1;
        float4 uv23 : TEXCOORD2;
        float4 uv45 : TEXCOORD3;
    };
    
    float4 offsets;
    
    sampler2D _MainTex;
    
    v2f vert (appdata_img v) {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);

        o.uv.xy = v.texcoord.xy;//正常uv
        //偏移值  沿左右上下进行偏移   六套UV,横竖12个偏移值
        o.uv01 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1);
        o.uv23 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 2.0;
        o.uv45 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 3.0;


        return o;
    }
    
    half4 frag (v2f i) : COLOR {
        half4 color = float4 (0,0,0,0);
        //根据权重叠加偏移后的颜色
        color += 0.40 * tex2D (_MainTex, i.uv);
        color += 0.15 * tex2D (_MainTex, i.uv01.xy);
        color += 0.15 * tex2D (_MainTex, i.uv01.zw);
        color += 0.10 * tex2D (_MainTex, i.uv23.xy);
        color += 0.10 * tex2D (_MainTex, i.uv23.zw);
        color += 0.05 * tex2D (_MainTex, i.uv45.xy);
        color += 0.05 * tex2D (_MainTex, i.uv45.zw);
        
        return color;
    }

    ENDCG
    
Subshader {
 Pass {
      ZTest Always Cull Off ZWrite Off
      Fog { Mode off }

      CGPROGRAM
      #pragma fragmentoption ARB_precision_hint_fastest
      #pragma vertex vert
      #pragma fragment frag
      ENDCG
  }
}

Fallback off


} // shader

放在物体上

Shader "Effects/FrostedGlass"
{
    Properties
    {
        _FrostTex ("Fross Texture", 2D) = "white" {}
        _FrostIntensity ("Frost Intensity", Range(0.0, 1.0)) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
        LOD 100
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uvfrost : TEXCOORD0;
                float4 uvgrab : TEXCOORD1;  
                float4 vertex : SV_POSITION;
            };

            sampler2D _FrostTex;
            float4 _FrostTex_ST;

            float _FrostIntensity;

            sampler2D _GrabBlurTexture_0;
            sampler2D _GrabBlurTexture_1;
            sampler2D _GrabBlurTexture_2;
            sampler2D _GrabBlurTexture_3;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uvfrost = TRANSFORM_TEX(v.uv, _FrostTex);
                o.uvgrab = ComputeGrabScreenPos(o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                float surfSmooth = 1-tex2D(_FrostTex, i.uvfrost) * _FrostIntensity;   //模糊强度贴图
                
                surfSmooth = clamp(0, 1, surfSmooth);//限制到0-1的区间

                half4 refraction;

                half4 ref00 = tex2Dproj(_GrabBlurTexture_0, i.uvgrab); //通过屏幕坐标采样抓到并模糊处理后的贴图
                half4 ref01 = tex2Dproj(_GrabBlurTexture_1, i.uvgrab);
                half4 ref02 = tex2Dproj(_GrabBlurTexture_2, i.uvgrab);
                half4 ref03 = tex2Dproj(_GrabBlurTexture_3, i.uvgrab);

                float step00 = smoothstep(0.75, 1.00, surfSmooth);//进行平滑过渡
                float step01 = smoothstep(0.5, 0.75, surfSmooth);
                float step02 = smoothstep(0.05, 0.5, surfSmooth);
                float step03 = smoothstep(0.00, 0.05, surfSmooth);

                refraction = lerp(ref03, lerp( lerp( lerp(ref03, ref02, step02), ref01, step01), ref00, step00), step03);
                
                return refraction;
            }
            ENDCG
        }
    }
}
 

C#

using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
[RequireComponent(typeof(Camera))]
public class CommandBufferBlur : MonoBehaviour
{
    Shader _Shader;

    Material _Material = null;

    Camera _Camera = null;
    CommandBuffer _CommandBuffer = null;

    Vector2 _ScreenResolution = Vector2.zero;
    RenderTextureFormat _TextureFormat = RenderTextureFormat.ARGB32;

    public void Cleanup()
    {
        if (!Initialized)
            return;

        _Camera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);
        _CommandBuffer = null;
        Object.DestroyImmediate(_Material);
    }

    public void OnEnable()
    {
        Cleanup();//先清理
        Initialize();//初始化
    }

    public void OnDisable()
    {
        Cleanup();
    }

    public bool Initialized
    {
        get { return _CommandBuffer != null; }
    }

    void Initialize()
    {
        if (Initialized)
            return;
        //根据shader创建材质球
        if (!_Shader)
        {
            _Shader = Shader.Find("Hidden/SeparableGlassBlur");

            if (!_Shader)
                throw new MissingReferenceException("Unable to find required shader \"Hidden/SeparableGlassBlur\"");
        }

        if (!_Material)
        {
            _Material = new Material(_Shader);
            _Material.hideFlags = HideFlags.HideAndDontSave;
        }
        //创建摄像机
        _Camera = GetComponent<Camera>();

        if (_Camera.allowHDR && SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.DefaultHDR))
            _TextureFormat = RenderTextureFormat.DefaultHDR;
        //创建commandbuffer
        _CommandBuffer = new CommandBuffer();
        _CommandBuffer.name = "Blur screen";

        int numIterations = 4;
        //屏幕尺寸
        Vector2[] sizes = {
            new Vector2(Screen.width, Screen.height),
            new Vector2(Screen.width / 2, Screen.height / 2),
            new Vector2(Screen.width / 4, Screen.height / 4),
            new Vector2(Screen.width / 8, Screen.height / 8),
        };

        for (int i = 0; i < numIterations; ++i)
        {
            int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
            _CommandBuffer.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear, _TextureFormat);
            //当前场景渲染到RT上
            _CommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);

            int blurredID = Shader.PropertyToID("_Grab" + i + "_Temp1");
            int blurredID2 = Shader.PropertyToID("_Grab" + i + "_Temp2");
            //申请两个临时缓存RT
            _CommandBuffer.GetTemporaryRT(blurredID, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
            _CommandBuffer.GetTemporaryRT(blurredID2, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);
            //降采样
            _CommandBuffer.Blit(screenCopyID, blurredID);
            _CommandBuffer.ReleaseTemporaryRT(screenCopyID);
            //横向偏移
            _CommandBuffer.SetGlobalVector("offsets", new Vector4(2.0f / sizes[i].x, 0, 0, 0));
            _CommandBuffer.Blit(blurredID, blurredID2, _Material);
            //纵向偏移
            _CommandBuffer.SetGlobalVector("offsets", new Vector4(0, 2.0f / sizes[i].y, 0, 0));
            _CommandBuffer.Blit(blurredID2, blurredID, _Material);
            //按照index输出RT
            _CommandBuffer.SetGlobalTexture("_GrabBlurTexture_" + i, blurredID);
        }
        //_Camera.AddCommandBuffer(CameraEvent.AfterForwardAlpha, _CommandBuffer);
        _Camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);

        _ScreenResolution = new Vector2(Screen.width, Screen.height);
    }

    void OnPreRender()
    {
        if (_ScreenResolution != new Vector2(Screen.width, Screen.height))
            Cleanup();

        Initialize();
    }
}

相关文章

  • 模糊shader总结(均值模糊,高斯模糊)

    效果排序 高斯+降采样>高斯>均值 CommandBuff的实现效果好,效率可控,但缺点是无法用在UI上 U...

  • 快速模糊算法

    图片模糊算法有均值模糊和高斯模糊,均值模糊快速但效果不如高斯,高斯模糊效果好但效率慢。 一种快速模糊算法:算法取自...

  • 7、高斯模糊

    均值模糊的扩展,权重均值模糊,效果比均值模糊好,应用场景毛玻璃 高斯分布,即正态分布 高斯模糊源码:其实就是模糊中...

  • 【Unity Shader入门精要学习】高级(三)

    屏幕后处理效果 高斯模糊 卷积的另一个常见应用就是高斯模糊。模糊的方法有很多,如均值模糊和中值模糊。均值模糊也是用...

  • 高斯模糊 Shader

    前言 咳咳,上篇文章《为什么选择 TypeScript ?》得到了许多朋友的认可,让我动力满满,以后要加油写出更多...

  • [Unity/shader]高斯模糊

    前言 很久没有学习新知识了,前端时间偶然翻了一下《shader入门精要》看了一下bloom效果,然后发现自己...

  • 008-Opencv笔记-均值模糊-高斯模糊

    模糊原理 Smooth/Blur 是图像处理中最简单和常用的操作之一使用该操作的原因之一就为了给图像预处理时候减低...

  • 图片模糊(高斯模糊)

    app的build.gradle配置:

  • shader实现屏幕高斯模糊

    实现屏幕模糊的方法有很多种,有均值模糊,中值模糊和高斯模糊。相信了解 过图像处理的对这些都会有一定的了解。这篇...

  • Unity Shader学习-高斯核演算学习

    模糊的方式 均值模糊 中值模糊 高斯模糊根据周边像素与中心像素的距离分配不同的权重,即离中心越近权重越大,反之越小...

网友评论

      本文标题:模糊shader总结(均值模糊,高斯模糊)

      本文链接:https://www.haomeiwen.com/subject/jcfpwktx.html