Unity Shader 屏幕后效果——高斯模糊
高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础。
实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客:
https://www.cnblogs.com/koshio0219/p/11137155.html
通过高斯方程计算出的卷积核称为高斯核,一个5*5的高斯核对它进行权重归一化如下:
0.0030 | 0.0133 | 0.0219 | 0.0133 | 0.0030 |
0.0133 | 0.0596 | 0.0983 | 0.0596 | 0.0133 |
0.0219 | 0.0983 | 0.1621 | 0.0983 | 0.0219 |
0.0133 | 0.0596 | 0.0983 | 0.0596 | 0.0133 |
0.0030 | 0.0133 | 0.0219 | 0.0133 | 0.0030 |
通过表也可以很清楚的看到,离原点越近的点模糊程度影响越大,反之越小。
为了优化计算,可以将这个5*5矩阵简化为两个矩阵分别计算,得到的效果是相同的。
它们分别是一个1*5的横向矩阵和一个5*1的纵向矩阵,这样我们只需要对横纵向矩阵分别进行一次采样既可,这样可以很大程度的减少计算量。
拆分之后结果如下:
我们发现,最终的计算只需要记录3个权重值既可,它们是weight[3]={0.4026,0.2442,0.0545};
具体实现:
1.实现调整高斯模糊参数的脚本。
为了进一步优化计算,这里加入了降采样系数,模糊范围缩放;为此,需要在外部增加模糊采样的迭代次数,具体如下:
1 using UnityEngine; 2 3 public class GaussianBlurCtrl : ScreenEffectBase 4 { 5 private const string _BlurSize = "_BlurSize";//只有模糊范围需要在GPU中计算 6 7 [Range(0, 4)] 8 public int iterations = 3;//迭代次数 9 [Range(0.2f, 3)] 10 public float blurSize = 0.6f;//模糊范围 11 [Range(1, 8)] 12 public int downSample = 2;//降采样系数 13 14 private void OnRenderImage(RenderTexture source, RenderTexture destination) 15 { 16 if (Material != null) 17 { 18 //得到屏幕的渲染纹理后直接除以降采样系数以成倍减少计算量,但过大时模糊效果不佳 19 int rtw = source.width/downSample; 20 int rth = source.height/downSample; 21 22 RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0); 23 buffer0.filterMode = FilterMode.Bilinear; 24 25 Graphics.Blit(source, buffer0); 26 27 //利用迭代次数对模糊范围加以控制,用到了类似于双缓冲的方式对纹理进行处理 28 for (int i = 0; i < iterations; i++) 29 { 30 //设置采样范围,根据迭代次数范围增加,之后会与纹理坐标进行乘积操作,固基础值为1 31 Material.SetFloat(_BlurSize, blurSize*i+1); 32 33 RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0); 34 Graphics.Blit(buffer0, buffer1, Material, 0); 35 //每次处理完立即释放相应缓存,因为Unity内部已经对此做了相应的优化 36 RenderTexture.ReleaseTemporary(buffer0); 37 buffer0 = RenderTexture.GetTemporary(rtw, rth, 0); 38 Graphics.Blit(buffer1, buffer0,Material, 1); 39 RenderTexture.ReleaseTemporary(buffer1); 40 } 41 Graphics.Blit(buffer0, destination); 42 RenderTexture.ReleaseTemporary(buffer0); 43 } 44 else 45 Graphics.Blit(source, destination); 46 } 47 }
基类脚本见:
https://www.cnblogs.com/koshio0219/p/11131619.html
2.在Shader中分别进行横向和纵向的模糊计算,分为两个Pass进行,具体如下:
1 Shader "MyUnlit/GaussianBlur" 2 { 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 SubShader 8 { 9 Tags { "RenderType"="Opaque" } 10 11 //CGINCLUDE中的代码可被其他Pass重复调用,用于简化不必要的重复代码 12 CGINCLUDE 13 14 #pragma multi_compile_fog 15 #include "UnityCG.cginc" 16 17 struct appdata 18 { 19 float4 vertex : POSITION; 20 float2 uv : TEXCOORD0; 21 }; 22 23 struct v2f 24 { 25 half2 uv[5] : TEXCOORD0; 26 UNITY_FOG_COORDS(1) 27 float4 pos : SV_POSITION; 28 }; 29 30 sampler2D _MainTex; 31 float4 _MainTex_TexelSize; 32 float _BlurSize; 33 34 //用于计算纵向模糊的纹理坐标元素 35 v2f vert_v(appdata v) 36 { 37 v2f o; 38 o.pos = UnityObjectToClipPos(v.vertex); 39 half2 uv = v.uv; 40 41 //以扩散的方式对数组进行排序,只偏移y轴,其中1和2,3和4分别位于原始点0的上下,且距离1个单位和2个像素单位 42 //得到的最终偏移与模糊范围的控制参数进行乘积 43 o.uv[0] = uv; 44 o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y*1.0)*_BlurSize; 45 o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y*1.0)*_BlurSize; 46 o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y*2.0)*_BlurSize; 47 o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y*2.0)*_BlurSize; 48 49 UNITY_TRANSFER_FOG(o, o.vertex); 50 return o; 51 } 52 53 //用于计算横向模糊的纹理坐标元素 54 v2f vert_h(appdata v) 55 { 56 v2f o; 57 o.pos = UnityObjectToClipPos(v.vertex); 58 half2 uv = v.uv; 59 60 //与上面同理,只不过是x轴向的模糊偏移 61 o.uv[0] = uv; 62 o.uv[1] = uv + float2( _MainTex_TexelSize.x*1.0,0.0)*_BlurSize; 63 o.uv[2] = uv - float2( _MainTex_TexelSize.x*1.0,0.0)*_BlurSize; 64 o.uv[3] = uv + float2( _MainTex_TexelSize.x*2.0,0.0)*_BlurSize; 65 o.uv[4] = uv - float2( _MainTex_TexelSize.x*2.0,0.0)*_BlurSize; 66 67 UNITY_TRANSFER_FOG(o, o.vertex); 68 return o; 69 } 70 71 //在片元着色器中进行最终的模糊计算,此过程在每个Pass中都会进行一次计算,但计算方式是统一的 72 fixed4 frag(v2f i) : SV_Target 73 { 74 float weights[3] = {0.4026,0.2442,0.0545}; 75 76 fixed4 col = tex2D(_MainTex, i.uv[0]); 77 78 fixed3 sum = col.rgb*weights[0]; 79 80 //对采样结果进行对应纹理偏移坐标的权重计算,以得到模糊的效果 81 for (int it = 1; it < 3; it++) 82 { 83 sum += tex2D(_MainTex, i.uv[2 * it - 1]).rgb*weights[it];//对应1和3,也就是原始像素的上方两像素 84 sum += tex2D(_MainTex, i.uv[2 * it]).rgb*weights[it];//对应2和4,下方两像素 85 } 86 fixed4 color = fixed4(sum, 1.0); 87 UNITY_APPLY_FOG(i.fogCoord, color); 88 return color; 89 } 90 91 ENDCG 92 93 ZTest Always 94 Cull Off 95 ZWrite Off 96 97 //纵向模糊Pass,直接用指令调用上面的函数 98 Pass 99 { 100 NAME "GAUSSIANBLUR_V" 101 CGPROGRAM 102 #pragma vertex vert_v 103 #pragma fragment frag 104 105 ENDCG 106 } 107 108 //横向模糊Pass 109 Pass 110 { 111 NAME "GAUSSIANBLUR_H" 112 CGPROGRAM 113 #pragma vertex vert_h 114 #pragma fragment frag 115 116 ENDCG 117 } 118 } 119 Fallback Off 120 }
效果如下:
转载于:https://www.cnblogs.com/koshio0219/p/11152534.html
Unity Shader 屏幕后效果——高斯模糊相关推荐
- Unity Shader 屏幕后效果——Bloom外发光
Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...
- Unity Shader·屏幕破碎效果
Unity Shader·屏幕破碎效果 前言 最近在做一个新的MMD(用Unity来实现),其中用到了一些好看的渲染技术在这里分享一下. 视频链接 https://www.bilibili.com/v ...
- unity 给图片边缘_Unity Shader 屏幕后效果——边缘检测
关于屏幕后效果的控制类详细见之前写的另一篇博客: 这篇主要是基于之前的控制类,实现另一种常见的屏幕后效果--边缘检测. 概念和原理部分: 首先,我们需要知道在图形学中经常处理像素的一种操作--卷积. ...
- Unity Shader·屏幕抖音效果
Unity Shader·屏幕抖音效果 前言 最近在做一个新的MMD(用Unity来实现),其中用到了一些好看的渲染技术在这里分享一下. 视频链接 https://www.bilibili.com/v ...
- Unity Shader 窗前雨滴效果衍生(表面水滴附着)
Unity Shader 窗前雨滴效果衍生(表面水滴附着) 霓虹中国视频截图 现实中的水珠附着效果 实现思路 1.首先创建一个Cube来作为实现效果的物体 2.创建一个Shader开始着色器的编写 实 ...
- Unity HilightingSystem屏幕后实现物体外发光描边效果
Unity实现物体外发光描边效果方式有好几种,如重叠放大模型描边Pass.卷积核描边.屏幕后处理等. HIightingSytem使用了屏幕后期效果实现,效果如下: 整理出核心代码如下,主要分为4个步 ...
- Unity Shader 之 透明效果
本文引用 Unity Shader入门精要 开启透明混合后,一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值外,还有--透明度.透明度为1,则完全不透明,透明度为0,则完全不会显示. 在Unity ...
- Unity Shader屏幕特效基础OnRenderImage()函数
前言: unity shader中的pass是会顺序执行的,但是由于在图像处理中我们常常需要使用一个pass的处理结果作为另一个pass的输入,这个时候就需要用到OnRenderImage()函数了 ...
- Unity Shader - 翻书效果
今天实现一个简单的翻书的效果,话不多说,先上一张效果图: 这里就随便用的一张纹理了,我们还是称为"翻木板"吧,哈哈. 实现过程: 其实这个效果实现起来还是挺简单的,大概思路其实就是 ...
最新文章
- 学C++,能不能简单点?
- IUSR_ 计算机名和IWAM_ 计算机名帐户的用户名和密码
- operator.itermgetter() (Python)
- 已锁定计算机,计算机锁定怎么解除_计算机已锁定如何解除
- express项目搭建 初始化详细步骤
- LeetCode 1130. 叶值的最小代价生成树(区间DP/单调栈贪心)
- 从数组到 HashMap 之算法解释
- 蓝桥杯 BEGIN-4 入门训练 Fibonacci数列
- Tabular学习笔记
- 步进电机和伺服驱动器接线
- meson和pkg-config
- 365投票抽奖助手V4.5.95版本小程序源码|前端+后端完整源码
- 算法可以申请专利么_华为突破封锁,对标谷歌Dropout专利,开源自研算法Disout...
- Jenkins+Gitlab+Ansible自动化部署(六)
- 计算机考研和不考研的区别,考研和不考研有什么区别?问清楚自己考研动机
- 还未挥洒热血,却道了离别(内涵高质量毕业答辩PPT模板)
- linux使用入门debian,Debian 7.7入门安装与配置
- 哥尼斯堡的“七桥问题”(C++)
- python unpacking_python packing unpacking 组包解包
- 网络状态码含义,常用(204,304, 404, 504,502)
热门文章
- 10.23 相对,绝对路径,cd,mkdir/rmdir,rm命令
- SOA与微服务基本原则及对比
- 安装vs 2015 x新建项目 显示(未将对象引用设置到对象实例) 处理方法
- poj 3258:River Hopscotch(二分)
- redis.conf 配置档详解
- 微信公众平台开发教程(四) 实例入门:机器人(附源码)
- [C#参考]锁定lock
- SQL Server 2008不能修改表的解决方法
- Struts2教程1:第一个Struts2程序
- contrastive loss function (papers)