Blur 算法 (Unity 5.0 Shader)

一:简单 Blur 算法

    一个像素的颜色值由其邻近的若干像素和自己的颜色值的平均值重新定义,以此达到模糊的效果。

    如下图,红色的像素点的值将由它和它周围的24个像素的平均值重新定义。计算的范围一般由一个“半径”来决定,表示由该点为中心、“半径”为距离

辐射的范围,对于下图“半径”为2。

image

二:shader代码

 1 Shader "Unlit/Blur"
 2 {
 3     Properties
 4     {
 5         _MainTex ("Texture", 2D) = "white" {}
 6         _Width("Image XRes", Float)  = 512
 7         _Height("Image YRes", Float) = 512
 8         _Radius("Radius", Range(0, 50)) = 4
 9     }
10 
11     SubShader
12     {
13         Tags { "RenderType"="Opaque" }
14         LOD 100
15 
16         Pass
17         {
18             CGPROGRAM
19             #pragma vertex vert
20             #pragma fragment frag
21             
22             #include "UnityCG.cginc"
23 
24             struct appdata
25             {
26                 float4 vertex : POSITION;
27                 float2 uv : TEXCOORD0;
28             };
29 
30             struct v2f
31             {
32                 float2 uv : TEXCOORD0;
33                 float4 vertex : SV_POSITION;
34             };
35 
36             sampler2D _MainTex;
37             float4 _MainTex_ST;
38             float _Width;
39             float _Height;
40             float _Radius;
41 
42             v2f vert (appdata v)
43             {
44                 v2f o;
45                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
46                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
47                 return o;
48             }
49             
50             fixed4 frag (v2f i) : SV_Target
51             {
52                 float horizontal = 1 / _Width;
53                 float vertical = 1 / _Height;
54 
55                 int radius = _Radius;
56                 int count = (2 * radius + 1) * (2 * radius + 1);
57                 fixed x = i.uv.x;
58                 fixed y = i.uv.y;
59 
60                 fixed4 col = fixed4(0,0,0,0);
61 
62                 for (int m = -radius; m <= radius; ++m) {
63                     fixed u = clamp(x + m * horizontal, 0, 1);
64                     for (int n = -radius; n <= radius; ++n) {
65                         fixed v = clamp(y + n * vertical, 0, 1);
66                         col += tex2D(_MainTex, fixed2(u, v));
67                     }
68                 }
69 
70                 return col / count;
71             }
72 
73             ENDCG
74         }
75     }
76 }

    因为unity shader并没有像glsl 3.0的textureSize这种获取texture尺寸的类似接口,需要定义两个Property : _Width和_Height,用于根据实际使

用的图片传入图片的尺寸。

    在shader中对于texture的像素点寻址是通过texture的uv坐标, 所以将计算移到UV坐标系进行。

    效果:从左到右是 原图、半径为5、半径为15

image image image

 

 

三:分析

  目前的设计存在的一个问题是当图片比较大的时候,运行效率会很低。相对比较耗时的操作为 第66行 代码 

col += tex2D(_MainTex, fixed2(u, v)),假设图片分辨率为1280 * 1024、半径为50,对于每一个像素都会执行一次

frag函数, 这第66行调用的次数为3409182720,属于10亿数量级,对于 2K、4K的图片就更不得了。

  对此,首先可以将半径的范围降低,加入为[0, 20]

 

posted @ 2016-06-29 14:03  KbDaVinci  阅读(1583)  评论(0编辑  收藏  举报