Unity Shader-后处理:高斯模糊
一.简介
二.概念介绍
1.正态分布
2.卷积
如果你每天都到地下去打台球,那么老板每天都要扇你一巴掌,不过当老板打你一巴掌后,你5分钟就消肿了,所以时间长了,你甚至就适应这种生活了……如果有一天,老板忍无可忍,以0.5秒的间隔开始不间断的扇你的过程,这样问题就来了,第一次扇你鼓起来的包还没消肿,第二个巴掌就来了,你脸上的包就可能鼓起来两倍高,老板不断扇你,脉冲不断作用在你脸上,效果不断叠加了,这样这些效果就可以求和了,结果就是你脸上的包的高度随时间变化的一个函数了(注意理解);如果老板再狠一点,频率越来越高,以至于你都辨别不清时间间隔了,那么,求和就变成积分了。可以这样理解,在这个过程中的某一固定的时刻,你的脸上的包的鼓起程度和什么有关呢?和之前每次打你都有关!但是各次的贡献是不一样的,越早打的巴掌,贡献越小,所以这就是说,某一时刻的输出是之前很多次输入乘以各自的衰减系数之后的叠加而形成某一点的输出,然后再把不同时刻的输出点放在一起,形成一个函数,这就是卷积,卷积之后的函数就是你脸上的包的大小随时间变化的函数。本来你的包几分钟就可以消肿,可是如果连续打,几个小时也消不了肿了,这难道不是一种平滑过程么?反映到剑桥大学的公式上,f(a)就是第a个巴掌,g(x-a)就是第a个巴掌在x时刻的作用程度,乘起来再叠加就ok了
三.高斯模糊的实现
- Shader "Custom/GaussianBlur"
- {
- Properties
- {
- _MainTex("Base (RGB)", 2D) = "white" {}
- }
- //通过CGINCLUDE我们可以预定义一些下面在Pass中用到的struct以及函数,
- //这样在pass中只需要设置渲染状态以及调用函数,shader更加简洁明了
- CGINCLUDE
- #include "UnityCG.cginc"
- //blur结构体,从blur的vert函数传递到frag函数的参数
- struct v2f_blur
- {
- float4 pos : SV_POSITION; //顶点位置
- float2 uv : TEXCOORD0; //纹理坐标
- float4 uv01 : TEXCOORD1; //一个vector4存储两个纹理坐标
- float4 uv23 : TEXCOORD2; //一个vector4存储两个纹理坐标
- float4 uv45 : TEXCOORD3; //一个vector4存储两个纹理坐标
- };
- //shader中用到的参数
- sampler2D _MainTex;
- //XX_TexelSize,XX纹理的像素相关大小width,height对应纹理的分辨率,x = 1/width, y = 1/height, z = width, w = height
- float4 _MainTex_TexelSize;
- //给一个offset,这个offset可以在外面设置,是我们设置横向和竖向blur的关键参数
- float4 _offsets;
- //vertex shader
- v2f_blur vert_blur(appdata_img v)
- {
- v2f_blur o;
- o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
- //uv坐标
- o.uv = v.texcoord.xy;
- //计算一个偏移值,offset可能是(0,1,0,0)也可能是(1,0,0,0)这样就表示了横向或者竖向取像素周围的点
- _offsets *= _MainTex_TexelSize.xyxy;
- //由于uv可以存储4个值,所以一个uv保存两个vector坐标,_offsets.xyxy * float4(1,1,-1,-1)可能表示(0,1,0-1),表示像素上下两个
- //坐标,也可能是(1,0,-1,0),表示像素左右两个像素点的坐标,下面*2.0,*3.0同理
- o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);
- o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;
- o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;
- return o;
- }
- //fragment shader
- fixed4 frag_blur(v2f_blur i) : SV_Target
- {
- fixed4 color = fixed4(0,0,0,0);
- //将像素本身以及像素左右(或者上下,取决于vertex shader传进来的uv坐标)像素值的加权平均
- color += 0.4 * tex2D(_MainTex, i.uv);
- color += 0.15 * tex2D(_MainTex, i.uv01.xy);
- color += 0.15 * tex2D(_MainTex, i.uv01.zw);
- color += 0.10 * tex2D(_MainTex, i.uv23.xy);
- color += 0.10 * tex2D(_MainTex, i.uv23.zw);
- color += 0.05 * tex2D(_MainTex, i.uv45.xy);
- color += 0.05 * tex2D(_MainTex, i.uv45.zw);
- return color;
- }
- ENDCG
- //开始SubShader
- SubShader
- {
- //开始一个Pass
- Pass
- {
- //后处理效果一般都是这几个状态
- ZTest Always
- Cull Off
- ZWrite Off
- Fog{ Mode Off }
- //使用上面定义的vertex和fragment shader
- CGPROGRAM
- #pragma vertex vert_blur
- #pragma fragment frag_blur
- ENDCG
- }
- }
- //后处理效果一般不给fallback,如果不支持,不显示后处理即可
- }
- using UnityEngine;
- using System.Collections;
- //编辑状态下也运行
- [ExecuteInEditMode]
- //继承自PostEffectBase
- public class GaussianBlur : PostEffectBase
- {
- //模糊半径
- public float BlurRadius = 1.0f;
- //降分辨率
- public int downSample = 2;
- //迭代次数
- public int iteration = 1;
- void OnRenderImage(RenderTexture source, RenderTexture destination)
- {
- if (_Material)
- {
- //申请RenderTexture,RT的分辨率按照downSample降低
- RenderTexture rt1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);
- RenderTexture rt2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);
- //直接将原图拷贝到降分辨率的RT上
- Graphics.Blit(source, rt1);
- //进行迭代高斯模糊
- for(int i = 0; i < iteration; i++)
- {
- //第一次高斯模糊,设置offsets,竖向模糊
- _Material.SetVector("_offsets", new Vector4(0, BlurRadius, 0, 0));
- Graphics.Blit(rt1, rt2, _Material);
- //第二次高斯模糊,设置offsets,横向模糊
- _Material.SetVector("_offsets", new Vector4(BlurRadius, 0, 0, 0));
- Graphics.Blit(rt2, rt1, _Material);
- }
- //将结果输出
- Graphics.Blit(rt1, destination);
- //释放申请的两块RenderBuffer内容
- RenderTexture.ReleaseTemporary(rt1);
- RenderTexture.ReleaseTemporary(rt2);
- }
- }
- }
四.效果展示
Unity Shader-后处理:高斯模糊的更多相关文章
- Unity Shader后处理-搜索灰度效果
如U3D中Hierarchy面板下的搜索效果: 讲解分析: 1.这种PostEffect效果其实就是指Unity shader的后处理,即游戏中实现屏幕特效的常见方法.顾名思义屏幕后处理就是指在渲染完 ...
- Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果
建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...
- Unity shader学习之屏幕后期处理效果之高斯模糊
高斯模糊,见 百度百科. 也使用卷积来实现,每个卷积元素的公式为: 其中б是标准方差,一般取值为1. x和y分别对应当前位置到卷积中心的整数距离. 由于需要对高斯核中的权重进行归一化,即使所有权重相加 ...
- 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)
写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...
- 【我的书】Unity Shader的书 — 目录(2016.5.19最后一次更新)
写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shad ...
- Unity Shader 阶段性反思与总结(一)
Unity Shader 阶段性反思与总结(一) 最近在写Shader的时候,总是感觉力不从心,感觉自己已经看了蛮久的书了,也有一定的积累了,但是一想写什么效果,完完全全就是脑袋一团空白.典型的例子就 ...
- 【转】《Unity Shader入门精要》冯乐乐著 书中彩图
为方便个人手机学习时候查阅,从网上转来这些彩图. 如属过当行为,联系本人删除. 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_s ...
- Unity Shader 知识点总结(二)
紧接着上一篇文章的shader入门知识的总结,本文主要总结shader中的纹理贴图.透明度混合.顶点动画.后期特效处理等操作.如果有什么地方有错,请指出更正,谢谢.本文的代码主要来自开源书:unity ...
- Unity Shader入门精要之 screen post-processing effect
本篇记录了学习Unity Shader入门精要的屏幕后处理的一些知识点. OnRenderImage(RenderTexture src, RenderTexture dest) 以上函数是Unity ...
- Unity Shader 入门精要学习 (冯乐乐 著)
第1篇 基础篇 第1章 欢迎来到Shader的世界 第2章 渲染流水线 第3章 Unity Shader 基础 第4章 学习Shader所需的数学基础 第2篇 初级篇 第5章 开始Unity Shad ...
随机推荐
- Android Menu用法全面讲解
说明:本文只介绍Android3.0及以上的Menu知识点. 菜单的分类 菜单是Android应用中非常重要且常见的组成部分,主要可以分为三类:选项菜单.上下文菜单/上下文操作模式以及弹出菜单.它们的 ...
- LeetCode(31): 下一个排列
Medium! 题目描述: (请仔细读题) 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列) ...
- 【python】已安装模块提示ImportError: No module named
今天遇到了一个问题,运行代码时出现错误 Traceback (most recent call last): File , in <module> import zmq ImportErr ...
- php工厂模式的实例
* 单例模式:用于创建单一类型的唯一实例对象 * 工厂模式:用于创建多种类型的多个实例对象 //声明形状类 class Shape { //声明静态方法create,根据容器形状不同,创建不同图形类的 ...
- 并行(多进程)-python
1.进程创建 2.当前进程信息 使用current_process可获得当前进程的信息: (1)引入:from multiprocessing import current_process (2)获取 ...
- MySQL5.7的新特性
MySQL 5.7版本据说已经在了很大的性能提升以及做得更加安全了,想了解更多MySQL 5.7的新特性可以参考我转载叶金荣老师的MySQL 5.7的新特性说明.这里我简单演示一下MySQL 5.7的 ...
- 《剑指offer》青蛙跳台阶
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 很裸的斐波那契数列. class Solution { public: int jumpFloor ...
- 【C++ Primer | 15】C++类内存分布
C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看编译器是怎么处理类成员内存分布的,特别是在继承.虚函数存在的情况下. 下面可以定义一个类,像下面这样: c ...
- Linux 下安装 MATLAB
MATLAB是美国MathWorks公司出品的商业数学软件,主要用于算法开发.数据可视化.数据分析以及数值计算的高级技术计算语言和交互式环境,是一款优秀而又强大的数学软件. 本文基于 Deepin 1 ...
- javax.inject包
javax.inject包 java提出的依赖注入标准,有别于以下传统的对象获取方式 构造方法 工厂模式 服务器定位模式(e.g. JNDI) 开发过程中是会有很多层层依赖的对象的,例如,Stopwa ...