Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)
速度映射图主要是为了得到每个像素相对于前一帧的运动矢量,其中一种方法是使用摄像机的深度纹理来推导。
推导过程如下:
先由深度纹理逆推出NDC(归一化的设备坐标)下的顶点坐标,利用VP矩阵(视角*投影矩阵)的逆矩阵反向变换出每个像素在世界空间中的位置,
再利用世界空间下的坐标与前一帧的VP矩阵顺向变换出前一帧的NDC坐标,利用NDC下前一帧和相当帧的坐标差来确定速度的方向,
最后利用速度的方向对纹理采样的结果进行加权平均并多次绘制,以达到带有物体运动方向的模糊效果。
基于这一原理,需要准备的要素有:
1.摄像机的深度纹理(是由NDC下的坐标映射来的,需要先反向映射回NDC)
2.当前帧的VP矩阵的逆矩阵
3.前一帧的VP矩阵
摄像机深度值和深度纹理的获取方法在之前的博客中有写,具体可以参考:
https://www.cnblogs.com/koshio0219/p/11178215.html
视角矩阵(V矩阵):
MyCamera.worldToCameraMatrix;(也就是世界空间变换到摄像机空间(也叫视角空间,观察空间))
投影矩阵(P矩阵):
MyCamera.projectionMatrix;(也就是摄像机空间变换到裁剪空间)
具体的数学推导过程可以见这篇文章:
http://feepingcreature.github.io/math.html
下面是具体的程序实现:
1.此脚本挂载在摄像机上,用于模糊参数调控,深度纹理准备,矩阵传递:
using UnityEngine; public class MotionBlurWithDepthTexCtrl : ScreenEffectBase
{
private const string _BlurSize = "_BlurSize";
private const string _PreViewMatrix = "_PreViewMatrix";
private const string _CurViewInserseMatrix = "_CurViewInserseMatrix"; [Range(0.0f, 1.0f)]
public float blurSize = .5f; //前一帧的VP矩阵
private Matrix4x4 preViewMatrix; private Camera myCamera;
public Camera MyCamera
{
get
{
if(null == myCamera)
{
myCamera = GetComponent<Camera>();
}
return myCamera;
}
} //开启这相机深度模式,并初始化前一帧的VP矩阵
private void OnEnable()
{
MyCamera.depthTextureMode |= DepthTextureMode.Depth; //右乘原则,前边是P矩阵,后边是V矩阵
preViewMatrix = MyCamera.projectionMatrix * MyCamera.worldToCameraMatrix;
} //不用时恢复
private void OnDisable()
{
MyCamera.depthTextureMode &= ~DepthTextureMode.Depth;
} private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Material)
{
Material.SetFloat(_BlurSize, blurSize);
//设置前一帧的VP矩阵
Material.SetMatrix(_PreViewMatrix, preViewMatrix);
//计算当前帧VP矩阵,右乘
Matrix4x4 curViewMatrix = MyCamera.projectionMatrix * MyCamera.worldToCameraMatrix;
//存起来,作为下次计算的前一帧
preViewMatrix = curViewMatrix;
//设置当前帧的VP矩阵的逆矩阵
Material.SetMatrix(_CurViewInserseMatrix, curViewMatrix.inverse); Graphics.Blit(source, destination, Material);
}
else
Graphics.Blit(source, destination); }
}
基类脚本见:
https://www.cnblogs.com/koshio0219/p/11131619.html
2.Shader脚本:
Shader "MyUnlit/MotionBlurWithDepthTex"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
ZTest Always Cull Off ZWrite Off CGPROGRAM
#pragma vertex vert
#pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex;
half4 _MainTex_TexelSize;
fixed _BlurSize;
//声明深度纹理和对应矩阵
sampler2D _CameraDepthTexture;
float4x4 _PreViewMatrix;
float4x4 _CurViewInserseMatrix; struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
}; struct v2f
{
//这里的的uv同时存了主纹理的uv和深度纹理uv,xy为主纹理,zw为深度纹理
half4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
}; v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy =v.uv;
o.uv.zw=v.uv; //主纹理外的纹理要进行平台差异化处理
#if UNITY_UV_STARTS_AT_TOP
if(_MainTex_TexelSize.y<)
o.uv.w=-o.uv.w;
#endif return o;
} fixed4 frag (v2f i) : SV_Target
{
//用深度纹理和zw取得深度值
float d=SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv.zw);
//反映射回NDC坐标,由[0,1]到[-1,1]的映射,z分量就是深度值本身
float4 H=float4(i.uv.x*-,i.uv.y*-,d*-,);
//用VP的逆矩阵反向变换并除以w分量得到世界坐标位置,为什么除以w详细见前面数学推导的文章链接
float4 D=mul(_CurViewInserseMatrix,H);
float4 worldPos=D/D.w; //分别得到前一帧和当前帧的NDC坐标取差值计算速度方向
float4 curViewPos=H;
float4 preViewPos=mul(_PreViewMatrix,worldPos);
preViewPos/=preViewPos.w; //除以的系数可以根据自己的需求调整
float2 velocity=(curViewPos.xy-preViewPos.xy)/10.0f; float2 uv=i.uv.xy;
//纹理采样的速度权重,这里进行了前2帧的计算,包括当前帧总共3个值,值依次递减且保证和为1,不为1则需要进行额外的除法
//目的是为了让越之前的帧看上去效果越淡,轨迹逐渐消失
float velColRate[]={0.6,0.3,0.1};
//当前采样结果用权重最大的值0.6
fixed4 col = tex2D(_MainTex, uv)*velColRate[];
uv+=velocity*_BlurSize; for(int it=;it<;it++)
{
//前两帧采样结果依次递减,0.3,0.1
fixed4 curCol=tex2D(_MainTex,uv.xy)*velColRate[it];
//将所有结果加起来,保证权重为1
col+=curCol;
//按速度方便对纹理进行偏移,并用模糊系数加以控制
uv+=velocity*_BlurSize;
} return fixed4(col.rgb,1.0);
}
ENDCG
}
}
FallBack Off
}
效果如下:

Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)的更多相关文章
- Unity Shader 屏幕后效果——颜色校正
屏幕后效果指的是,当前整个场景图已经渲染完成输出到屏幕后,再对输出的屏幕图像进行的操作. 在Unity中,一般过程通常是: 1.建立用于处理效果的shader和临时材质,给shader脚本传递需要控制 ...
- Unity Shader 屏幕后效果——边缘检测
关于屏幕后效果的控制类详细见之前写的另一篇博客: https://www.cnblogs.com/koshio0219/p/11131619.html 这篇主要是基于之前的控制类,实现另一种常见的屏幕 ...
- Unity Shader 屏幕后效果——全局雾
Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便.这里利用屏幕后处理产生可单独控制且自由度更高的雾效. 屏幕后雾效的本质在于,通过深度纹理重构出每个像素在世界空间中的位置,根据得 ...
- Unity Shader 屏幕后效果——景深
景深效果的原理是,在摄像机的近裁剪平面和远裁剪平面之间可以设置一个焦距,在这个距离所在的平面上的物体最为清晰,而这个距离之前或之后的物体成像是一种模糊状态(根据距离逐渐模糊,最终达到最为模糊的状态). ...
- Unity Shader 屏幕后效果——高斯模糊
高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础. 实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客: https://www.cnblogs.c ...
- Unity Shader 屏幕后效果——Bloom外发光
Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...
- Unity shader学习之屏幕后期处理效果之运动模糊
运动模糊,代码如下: using UnityEngine; public class MotionBlurRenderer : PostEffectRenderer { [Range(0.1f, 0. ...
- Unity Shader实现描边效果
http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...
- Unity Shader 之 透明效果
透明效果 透明效果一般有两种实现方法: 第一种,使用透明度测试(Alpha Test) 第二种,使用透明度混合(Alpha Blending) 透明度测试和透明度混合机制: 透明度测试(Alpha T ...
随机推荐
- 图解Java常用数据结构
最近在整理数据结构方面的知识, 系统化看了下 Java 中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于 jdk8, 可能会有些特性与 jdk7 之前不相同, 例如 LinkedList ...
- pandas.read_sql_query()读取数据库数据用chunksize的坑
最近一项工作需要读取数据库中1500万条数据,考虑到数据量太大,不方便直接一次性读取,不然会内存爆炸.想到用pandas.read_sql_query()里有一个chunksize可以分批返回chun ...
- centos7之firewalld防火墙的配置与使用
firewalld是centos7开始提供的管理防火墙工具,提供了一个动态管理的防火墙,当然低层仍然调用的是 netfilter . 一.区域(zone)firewalld将网卡对应到不同的区域(zo ...
- 什么是SFP光模块?
什么是光模块? 光模块(optical module)由光电子器件.功能电路和光接口等组成,光电子器件包括发射和接收两部分.简单的说,光模块的作用就是光电转换,发送端把电信号转换成光信号,通过光纤传送 ...
- Java电商项目-1.构建数据库,搭建项目环境
目录 到Github获取源码请点击此处 一. 数据库还原 二. Mybatis逆向生成工具的使用 三. 搭建项目环境 四. 在linux虚拟机上部署zookeeper, 搭建Dubbo服务. linu ...
- Python 使用 PyMysql、DBUtils 创建连接池,提升性能
转自:https://blog.csdn.net/weixin_41287692/article/details/83413775 Python 编程中可以使用 PyMysql 进行数据库的连接及诸如 ...
- Python-警告处理
python 下Warning的使用 起因是这样的,当我使用pymysql模块执行建表的sql语句时获,在控制台输出了红色的消息,但是程序并没有终止而是继续运行了 sql语句如下: CREATE TA ...
- java主函数
相信很多初次接触java的同学,在遇见主函数的时候,听到最多的就是主函数的格式是固定的,不能进行修改等等.这就让人疑惑了,主函数为啥就那么特殊呢?接下来博主会为大家解释主函数.大家先看看下面这个程序: ...
- JavaWeb之Fliter & Listener
Fliter & Listener Listener 监听器 作用 监听某一事件的发生.状态的改变. 监听器内部实现机制 接口回调 接口回调 A在执行循环,当循环到5的时候, 通知B. 事先先 ...
- 安卓开发笔记(三十四):Material Design框架实现优美的左侧侧滑栏
首先我们先上图: 下面是主页面的代码,activity_main.xml: <?xml version="1.0" encoding="utf-8"?& ...