zoukankan      html  css  js  c++  java
  • Unity shader学习之屏幕后期处理效果之高斯模糊

    高斯模糊,见 百度百科

    也使用卷积来实现,每个卷积元素的公式为:

    其中б是标准方差,一般取值为1。

    x和y分别对应当前位置到卷积中心的整数距离。

    由于需要对高斯核中的权重进行归一化,即使所有权重相加为1,因此e前面的系数实际不会对结果产生任何影响。

    转载请注明出处:http://www.cnblogs.com/jietian331/p/7238032.html

    综上,公式简化为:

    G(x,y) = e-(x*x+y*y)/2

    因此,高斯核计算代码如下:

      1 using System;
      2 
      3 namespace TestShell
      4 {
      5     class Program
      6     {
      7         static void Main(string[] args)
      8         {
      9             Console.WriteLine("输入需要得到的高斯卷积核的维数(如3,5,7...):");
     10 
     11             string input = Console.ReadLine();
     12             int size;
     13 
     14             if (!int.TryParse(input, out size))
     15             {
     16                 Console.WriteLine("不是数字...");
     17                 return;
     18             }
     19 
     20             // 计算
     21             double[] r2 = null;
     22             double[,] r = null;
     23             try
     24             {
     25                 r = CalcGaussianBlur(size, out r2);
     26             }
     27             catch (Exception ex)
     28             {
     29                 Console.WriteLine("错误: " + ex.Message);
     30             }
     31 
     32             if (r != null && r2 != null)
     33             {
     34                 // 卷积如下:
     35                 Console.WriteLine();
     36                 Console.WriteLine("{0}x{0}的高斯卷积核如下:", size);
     37                 for (int i = 0; i < r.GetLongLength(0); i++)
     38                 {
     39                     for (int j = 0; j < r.GetLongLength(1); j++)
     40                     {
     41                         Console.Write("{0:f4}	", r[i, j]);
     42                     }
     43                     Console.WriteLine();
     44                 }
     45                 Console.WriteLine();
     46 
     47                 Console.WriteLine("可拆成2个一维的数组:");
     48                 for (int i = 0; i < r2.Length; i++)
     49                 {
     50                     Console.Write("{0:f4}	", r2[i]);
     51                 }
     52                 Console.WriteLine();
     53                 Console.WriteLine();
     54 
     55                 Console.WriteLine("验证,使用这2个一维的数组也可以得到同样的结果:");
     56                 for (int i = 0; i < size; i++)
     57                 {
     58                     for (int j = 0; j < size; j++)
     59                     {
     60                         Console.Write("{0:f4}	", r2[i] * r2[j]);
     61 
     62                     }
     63                     Console.WriteLine();
     64                 }
     65             }
     66 
     67             Console.WriteLine();
     68             Console.WriteLine("按任意键结束...");
     69             Console.ReadKey();
     70         }
     71 
     72         static double[,] CalcGaussianBlur(int size, out double[] r2)
     73         {
     74             if (size < 3)
     75                 throw new ArgumentException("size < 3");
     76             if (size % 2 != 1)
     77                 throw new ArgumentException("size % 2 != 1");
     78 
     79             double[,] r = new double[size, size];
     80             r2 = new double[size];
     81             int center = (int)Math.Floor(size / 2f);
     82             double sum = 0;
     83 
     84             for (int i = 0; i < size; i++)
     85             {
     86                 for (int j = 0; j < size; j++)
     87                 {
     88                     int x = Math.Abs(i - center);
     89                     int y = Math.Abs(j - center);
     90                     double d = CalcItem(x, y);
     91                     r[i, j] = d;
     92                     sum += d;
     93                 }
     94             }
     95 
     96             for (int i = 0; i < size; i++)
     97             {
     98                 for (int j = 0; j < size; j++)
     99                 {
    100                     r[i, j] /= sum;
    101                     if (i == j)
    102                         r2[i] = Math.Sqrt(r[i, i]);
    103                 }
    104             }
    105 
    106             return r;
    107         }
    108 
    109         static double CalcItem(int x, int y)
    110         {
    111             return Math.Pow(Math.E, -(x * x + y * y) / 2d);
    112         }
    113     }
    114 }
    View Code

    工具在: http://files.cnblogs.com/files/jietian331/CalcGaussianBlur.zip

    一个5 x 5的高斯核如下:

    使用2个一维数组可简化计算量,提高性能,通过观察可知,只需要计3个数:

    使用unity shader屏幕后期处理来实现高斯模糊,代码如下。

    子类:

     1 using UnityEngine;
     2 
     3 public class GaussianBlurRenderer : PostEffectRenderer
     4 {
     5     [Range(1, 8)]
     6     [SerializeField]
     7     public int m_downSample = 2;      // 降采样率
     8     [Range(0, 4)]
     9     [SerializeField]
    10     public int m_iterations = 3;        // 迭代次数
    11     [Range(0.2f, 3f)]
    12     [SerializeField]
    13     public float m_blurSpread = 0.6f;        // 模糊扩散量
    14 
    15     protected override void OnRenderImage(RenderTexture src, RenderTexture dest)
    16     {
    17         int w = (int)(src.width / m_downSample);
    18         int h = (int)(src.height / m_downSample);
    19         RenderTexture buffer0 = RenderTexture.GetTemporary(w, h);
    20         RenderTexture buffer1 = RenderTexture.GetTemporary(w, h);
    21         buffer0.filterMode = FilterMode.Bilinear;
    22         buffer1.filterMode = FilterMode.Bilinear;
    23         Graphics.Blit(src, buffer0);
    24 
    25         for (int i = 0; i < m_iterations; i++)
    26         {
    27             Mat.SetFloat("_BlurSpread", 1 + i * m_blurSpread);
    28 
    29             Graphics.Blit(buffer0, buffer1, Mat, 0);
    30             Graphics.Blit(buffer1, buffer0, Mat, 1);
    31         }
    32 
    33         Graphics.Blit(buffer0, dest);
    34         RenderTexture.ReleaseTemporary(buffer0);
    35         RenderTexture.ReleaseTemporary(buffer1);
    36     }
    37 
    38     protected override string ShaderName
    39     {
    40         get { return "Custom/Gaussian Blur"; }
    41     }
    42 }
    GaussianBlurRenderer

    shader:

     1 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
     2 
     3 Shader "Custom/Gaussian Blur"
     4 {
     5     Properties
     6     {
     7         _MainTex("Main Texture", 2D) = "white" {}
     8         _BlurSpread("Blur Spread", float) = 1
     9     }
    10 
    11     SubShader
    12     {
    13         CGINCLUDE
    14         
    15         sampler2D _MainTex;
    16         float4 _MainTex_TexelSize;
    17         uniform float _BlurSpread;
    18 
    19         struct appdata
    20         {
    21             float4 vertex : POSITION;
    22             float2 uv : TEXCOORD0;
    23         };
    24 
    25         struct v2f
    26         {
    27             float4 pos : SV_POSITION;
    28             float2 uv[5] : TEXCOORD0;
    29         };
    30 
    31         v2f vertHorizontal(appdata v)
    32         {
    33             v2f o;
    34             o.pos = UnityObjectToClipPos(v.vertex);
    35             float tsx = _MainTex_TexelSize.x * _BlurSpread;
    36             o.uv[0] = v.uv + float2(tsx * -2, 0);
    37             o.uv[1] = v.uv + float2(tsx * -1, 0);
    38             o.uv[2] = v.uv;
    39             o.uv[3] = v.uv + float2(tsx * 1, 0);
    40             o.uv[4] = v.uv + float2(tsx * 2, 0);
    41             return o;
    42         }
    43 
    44         v2f vertVertical(appdata v)
    45         {
    46             v2f o;
    47             o.pos = UnityObjectToClipPos(v.vertex);
    48             float tsy = _MainTex_TexelSize.y * _BlurSpread;
    49             o.uv[0] = v.uv + float2(0, tsy * -2);
    50             o.uv[1] = v.uv + float2(0, tsy * -1);
    51             o.uv[2] = v.uv;
    52             o.uv[3] = v.uv + float2(0, tsy * 1);
    53             o.uv[4] = v.uv + float2(0, tsy * 2);
    54             return o;
    55         }
    56 
    57         fixed4 frag(v2f i) : SV_TARGET
    58         {
    59             float g[3] = {0.0545, 0.2442, 0.4026};
    60             fixed4 col = tex2D(_MainTex, i.uv[2]) * g[2];
    61             for(int k = 0; k < 2; k++)
    62             {
    63                 col += tex2D(_MainTex, i.uv[k]) * g[k];
    64                 col += tex2D(_MainTex, i.uv[4 - k]) * g[k];
    65             }
    66             return col;
    67         }
    68 
    69         ENDCG
    70 
    71         Pass
    72         {
    73             Name "HORIZONTAL"
    74             ZTest Always
    75             ZWrite Off
    76             Cull Off
    77 
    78             CGPROGRAM
    79             #pragma vertex vertHorizontal
    80             #pragma fragment frag
    81             ENDCG
    82         }
    83 
    84         Pass
    85         {
    86             Name "VERTICAL"
    87             ZTest Always
    88             ZWrite Off
    89             Cull Off
    90 
    91             CGPROGRAM
    92             #pragma vertex vertVertical
    93             #pragma fragment frag
    94             ENDCG
    95         }
    96     }
    97 
    98     Fallback Off
    99 }
    Custom/Gaussian Blur

    调整参数:

    DownSample,即降采样率,越大性能越好,图像越模糊,但过大可能会使图像像素化。

    Iteraitions, 即迭代次数,越大图像模糊效果越好,但性能也会下降。

    BlurSpread,即模糊扩散量,越大图像越模糊,但过大会造成虚影。

    效果如下:

     

  • 相关阅读:
    Python 获取校内(人人网)的所有好友照片存储到本地
    Learning DNN Module Developers guide
    第一次用blog
    杂谈:淘宝商城“暴动”事件
    百度三维地图体验(坑爹啊有图有真相)
    从历史的角度杂谈《中国没有乔布斯,美国没有史玉柱》说起
    南漂一年个人随想录
    我离淘宝有多远?
    centos搭建Git分布式管理控制系统
    乔布斯与中国
  • 原文地址:https://www.cnblogs.com/jietian331/p/7238032.html
Copyright © 2011-2022 走看看