Unity Shader 学习笔记(21) 模糊、高斯模糊

来源:互联网 发布:启动mysql 编辑:程序博客网 时间:2024/05/22 15:13

Unity Shader 学习笔记(21) 模糊、高斯模糊

参考书籍:《Unity Shader 入门精要》
GaussianBlur类源码:GaussianBlur.cs


模糊

  • 均值模糊:卷积核各个元素都相等,且相加为1。即卷积后得到像素值是邻域内各像素平均值。
  • 中值模糊:即邻域内所有像素排序后中间那个,替换掉原颜色。
  • 高斯模糊:使用卷积核称作高斯核,高斯核是正方形的滤波核。

高斯模糊

高斯方程如下。σ为标准方差(一般为1)。即离得越近,影响越大,越模糊。

对应类似如下图的正态分布:

因为高斯核是正态分布的,所以可以简化高斯核:

迭代次数逐渐提高,每次迭代模糊采样跨度扩大,性能消耗增加:

迭代次数不变下(一次),提高模糊采样跨度:

减小屏幕获取纹理大小,性能消耗减小,可能会像素化:

GaussianBlur类(省略其他两个版本,可见最上方源码):

public class GaussianBlur : PostEffectsBase{    [Range(0, 4)]    public int iterations = 3;                  // 模糊迭代次数    [Range(0.2f, 3.0f)]    public float blurSpread = 0.6f;             // 模糊范围,过大会造成虚影    [Range(1, 8)]    public int downSample = 2;                  // 减少采样倍数的平方。越大,处理像素越少,过大可能会像素化    void OnRenderImage(RenderTexture src, RenderTexture dest)    {        if (TargetMaterial != null)        {            int rtW = src.width / downSample;            int rtH = src.height / downSample;            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);            RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);            buffer0.filterMode = FilterMode.Bilinear;            Graphics.Blit(src, buffer0);                            // 用到所有Pass块            // buffer0 存将要被处理的缓存,buffer1存搞好的            for (int i = 0; i < iterations; i++)            {                material.SetFloat("_BlurSize", 1.0f + (i + 1) * blurSpread);                Graphics.Blit(buffer0, buffer1, material, 0);                Graphics.Blit(buffer1, buffer0, material, 1);            }            Graphics.Blit(buffer0, dest);            RenderTexture.ReleaseTemporary(buffer0);            RenderTexture.ReleaseTemporary(buffer1);        }        else            Graphics.Blit(src, dest);    }}

Shader:

Properties {    _MainTex ("Base (RGB)", 2D) = "white" {}    _BlurSize ("Blur Size", Float) = 1.0        // 模糊采样距离,过大会产生虚影}SubShader {    // 类似C++头文件功能。使用时不用包含在Pass块,Pass中直接指定顶点和片元着色器,可避免编写两个一样的frag函数    CGINCLUDE    ...    struct v2f {        float4 pos : SV_POSITION;        half2 uv[5]: TEXCOORD0;    };    // appdata_img定义在UnityCG.cginc    v2f vertBlurVertical(appdata_img v) {        v2f o;        o.pos = UnityObjectToClipPos(v.vertex);        half2 uv = v.texcoord;        o.uv[0] = uv;        o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;        o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;        o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;        o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;        return o;    }    v2f vertBlurHorizontal(appdata_img v) {        ... // 类似处理垂直模糊的顶点着色器    }    // 两个Pass公用片元着色器    fixed4 fragBlur(v2f i) : SV_Target {        float weight[3] = {0.4026, 0.2442, 0.0545};        fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];      // 中间点        // 另外四个点        for (int it = 1; it < 3; it++) {            sum += tex2D(_MainTex, i.uv[it*2-1]).rgb * weight[it];  // 和下面对称的点            sum += tex2D(_MainTex, i.uv[it*2]).rgb * weight[it];        }        return fixed4(sum, 1.0);    }    ENDCG    ZTest Always Cull Off ZWrite Off    Pass {        NAME "GAUSSIAN_BLUR_VERTICAL"           // 定义名字。可以从其他Shader直接来使用该Pass        CGPROGRAM        #pragma vertex vertBlurVertical          #pragma fragment fragBlur        ENDCG      }    Pass {          NAME "GAUSSIAN_BLUR_HORIZONTAL"        CGPROGRAM          #pragma vertex vertBlurHorizontal          #pragma fragment fragBlur        ENDCG    }} 
原创粉丝点击