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 ...
随机推荐
- java多线程快速入门(十二)
在静态方法上面加synchonizd用的是字节码文件锁 package com.cppdy; class MyThread8 implements Runnable { private static ...
- JavaScript常见的假值
值 说明 var a=false; 值等于false(假) var a =0; 值等于0 var a=''; 空的字符串 var a=10/'abc' NaN var a; 未赋值变量
- bootstrap 全局样式设置
HTML <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" co ...
- ERP退货系统管理(四十五)
添加的存储过程:(添加退货申请信息的存储过程) CREATE PROCEDURE [dbo].[BioBackSendGoods_ADD] @SendBackID INT OUTPUT, ), @Ap ...
- C#对Windows文件/文件夹/目录的一些操作总结
1. 在一个目录下创建一个文件夹 if (!System.IO.Directory.Exists(path)) System.IO.Directory.CreateDirectory(path); ...
- POJ - 3080 Blue Jeans 【KMP+暴力】(最大公共字串)
<题目链接> 题目大意: 就是求k个长度为60的字符串的最长连续公共子串,2<=k<=10 限制条件: 1. 最长公共串长度小于3输出 no significant co ...
- NPM 上传自己的包
NPM 上传自己的包 项目中经常 npm install,npm init啥的,那么如何上传自己的包到npm上呢. 注册账号 NPM官网 本地弄一个包 创建npm_test 文件夹 注:不能够有一些特 ...
- Coredata 单表简单使用
** 使用Coredata 工程中的DataModel创建:系统创建.手动创建** ** 使用Coredata需要要导入<CoreData/CoreData.h> ** 1.系统创建(系统 ...
- Git学习笔记:基础篇
git可以说是所有开发者出开发语言之外的最基本的基本功了,熟悉git可以方便的进行代码版本控制,以及与其他开发者进行合作开发.本文内容是我以往学习git时做的笔记,主要是关于git最基本的操作,但 只 ...
- 【Java】基本I/O的学习总结
计算机I/O 理解IO先要知道计算机对数据的输入输出是怎么处理的,下面一张图可以大致理解: 可以看出所谓输入是外部数据向CPU输入,而输出是CPU将数据输出到我们可见的地方,例如文件.屏幕等.而计算机 ...