UnityShader : 高斯模糊 Gaussian Blur
2015-07-20 22:40
746 查看
通常我们会比较在意图片的清晰度,想要图片越精细,那自然会想到像素要高了,像素的意义就是保存更多的颜色信息,这样图片就能表现更多的细节。相反,要达到模糊效果,自然就是将颜色信息舍弃掉,通过不同的算法,得到的模糊效果也会不一样。
开始写Shader, 先定义可调节的参数
然后编写出取平均颜色的函数
其他代码我就不贴了,后面介绍高斯模糊的时候贴出完整shader,有兴趣的话可以将这个函数修改进去。
看到没,右边就是模糊后的效果图,我这里设置的取值半径为5
这就是普通的模糊效果,我一开始也分不清高斯模糊有什么特殊的,直到我做了对比之后。。。
我们先来看看高斯模糊的算法
高斯分布,即正态分布曲线,形状大概如下图:
它就是一个可以计算出符合上面要求的权重分布的函数,对应的二维形式如下:
使用高斯分布曲线作为滤镜算法的模糊算法,称之为高斯模糊。
首先我们需要一个求权重的函数
接下来我们就要开始写具体的模糊函数了。大致思路就是根据位置获取相应的颜色乘以算出来的权重,得出来的颜色信息总和就是最终的颜色。
这其中权重我算了两边,因为我们只取了1/3的半径,所以我们需要归一,就是记录总和,然后让每个权重除以这个总和。这样才能保证所有的权重加起来为1,要不然会出现颜色丢失现象,会导致整体颜色变暗。
(这里没有做优化处理,只是为了方便理解。 实际使用中完全可以将权重设定为常量而不需要每次计算。)
中间的为普通的模糊,好像近视眼一样,有重影
右边高斯模糊就比较平缓
取值半径为10的模糊效果
当然实际使用中不建议取值半径算这么大。可以进行多次模糊迭代计算,效果更佳。我这里介绍的是二维高斯运算,可以尝试使用一维运算,然后X,Y各模糊一次。
具体可以参考U3D Image effect 包里面的Blur实现方式,
普通的模糊算法
比较普通的一种,就是将每个像素的颜色,都与周边的颜色靠拢,丢失自己独特的颜色,也就是取自己与周围颜色的平均值,从而达到模糊的效果。开始写Shader, 先定义可调节的参数
//因为shader取值都是百分比,所以我们要定出贴图的尺寸来进行计算 _TextureSize ("_TextureSize",Float) = 256 //取值半径 _BlurRadius ("_BlurRadius",Range(1,15) ) = 1
然后编写出取平均颜色的函数
float4 GetBlurColor( float2 uv ) { float space = 1.0/_TextureSize; //算出一个像素的空间 int count = _BlurRadius * 2 +1; //取值范围 count *= count; //将以自己为中心,周围半径的所有颜色相加,然后除以总数,求得平均值 float4 colorTmp = float4(0,0,0,0); for( int x = -_BlurRadius ; x <= _BlurRadius ; x++ ) { for( int y = -_BlurRadius ; y <= _BlurRadius ; y++ ) { float4 color = tex2D(_MainTex,uv + float2(x * space,y * space)); colorTmp += color; } } return colorTmp/count; }
其他代码我就不贴了,后面介绍高斯模糊的时候贴出完整shader,有兴趣的话可以将这个函数修改进去。
看到没,右边就是模糊后的效果图,我这里设置的取值半径为5
这就是普通的模糊效果,我一开始也分不清高斯模糊有什么特殊的,直到我做了对比之后。。。
我们先来看看高斯模糊的算法
高斯模糊
如上所说,模糊的手段,就是让像素与周围的像素颜色平滑起来。上面使用简单平均,这样其实不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。这个时候我们就需要用到高斯曲线了。高斯分布,即正态分布曲线,形状大概如下图:
它就是一个可以计算出符合上面要求的权重分布的函数,对应的二维形式如下:
使用高斯分布曲线作为滤镜算法的模糊算法,称之为高斯模糊。
高斯模糊算法实现
流程跟上面的一样,只不过这里我们需要用到高斯模糊的曲线函数来计算权重,来替代之前简单的平均取值。首先我们需要一个求权重的函数
//计算权重 float GetGaussianDistribution( float x, float y, float rho ) { float g = 1.0f / sqrt( 2.0f * 3.141592654f * rho * rho ); return g * exp( -(x * x + y * y) / (2 * rho * rho) ); }
接下来我们就要开始写具体的模糊函数了。大致思路就是根据位置获取相应的颜色乘以算出来的权重,得出来的颜色信息总和就是最终的颜色。
float4 GetGaussBlurColor( float2 uv ) { //算出一个像素的空间 float space = 1.0/_TextureSize; //参考正态分布曲线图,可以知道 3σ 距离以外的点,权重已经微不足道了。 //反推即可知道当模糊半径为r时,取σ为 r/3 是一个比较合适的取值。 float rho = (float)_BlurRadius * space / 3.0; //---权重总和 float weightTotal = 0; for( int x = -_BlurRadius ; x <= _BlurRadius ; x++ ) { for( int y = -_BlurRadius ; y <= _BlurRadius ; y++ ) { weightTotal += GetGaussianDistribution(x * space, y * space, rho ); } } //-------- float4 colorTmp = float4(0,0,0,0); for( int x = -_BlurRadius ; x <= _BlurRadius ; x++ ) { for( int y = -_BlurRadius ; y <= _BlurRadius ; y++ ) { float weight = GetGaussianDistribution( x * space, y * space, rho )/weightTotal; float4 color = tex2D(_MainTex,uv + float2(x * space,y * space)); color = color * weight; colorTmp += color; } } return colorTmp; }
这其中权重我算了两边,因为我们只取了1/3的半径,所以我们需要归一,就是记录总和,然后让每个权重除以这个总和。这样才能保证所有的权重加起来为1,要不然会出现颜色丢失现象,会导致整体颜色变暗。
(这里没有做优化处理,只是为了方便理解。 实际使用中完全可以将权重设定为常量而不需要每次计算。)
效果图对比
下面是取值半径为5的效果对比图。应该能明显看出区别了。中间的为普通的模糊,好像近视眼一样,有重影
右边高斯模糊就比较平缓
取值半径为10的模糊效果
当然实际使用中不建议取值半径算这么大。可以进行多次模糊迭代计算,效果更佳。我这里介绍的是二维高斯运算,可以尝试使用一维运算,然后X,Y各模糊一次。
具体可以参考U3D Image effect 包里面的Blur实现方式,
Shader
剩下的代码贴出,把上面的函数拷贝进去就好了,我就不重复贴了。Shader "Custom/GaussBlur" { Properties { _MainTex ("Albedo (RGB)", 2D) = "white" {} _TextureSize ("_TextureSize",Float) = 256 _BlurRadius ("_BlurRadius",Range(1,15) ) = 5 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; int _BlurRadius; float _TextureSize; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert( appdata_img v ) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; return o; } /* 将上面的函数拷贝进来 */ half4 frag(v2f i) : SV_Target { //调用普通模糊 //return GetBlurColor(i.uv); //调用高斯模糊 //return GetGaussBlurColor(i.uv); return tex2D(_MainTex,i.uv); } ENDCG } } FallBack "Diffuse" }
相关文章推荐
- Python中使用PIL库实现图片高斯模糊实例
- 反编译ARB program to GLSL shader日记
- 虚幻3引擎
- 基于顶点纹理的无限大海水仿真
- 图形加速卡技术 [专业的基础技术文章]
- 关于VR(主要是虚拟城市场景)的一些想法及实现(可能会连载)
- 编译ics
- 项目中的简单shader
- Simulating Ocean Water
- 在c++中模以”委托“
- 关于NGUI中UITexture贴图自定义的shader文件在UISrollView中不报错的解决方案
- OpenGL&D3D State Machine
- 得到一个 a4e9 bitmap的倒影
- DirectX 8 开发者常见问题集
- error X3025:global variebles are implicitly constant,enable compatibility mode to allow modificatiom
- dx编译shader报错:global variables are implicitly constant, enable compatibility mode to...
- 2016年的游戏引擎设计
- 纹理过滤模式中的Bilinear、Trilinear以及Anistropic Filtering
- Bump Mapping综述
- 一个简单例子表示fixed functional VS/Assemble VS/HLSI VS的例子