美文网首页
模糊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总结(均值模糊,高斯模糊)

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