【Unity Shader入门精要 第13章】使用深度和法线纹理(二)

1. 再谈运动模糊

之前的文章中曾经通过保存渲染结果进行叠加的方式实现过运动模糊效果,下面的例子我们通过深度纹理重建世界坐标的方式来实现运动模糊:

  • 首先,基于深度纹理重建像素的世界坐标,原理在【Unity Shader入门精要 第13章】使用深度和法线纹理(一)中介绍过
  • 然后使用保存的前一帧的VP矩阵进行矩阵变换,求出前一帧的NDC坐标
  • 通过两帧的NDC坐标计算像素的速度
  • 最后通过速度进行模糊处理

由于需要对摄像机进行操作,为了方便拿到当前摄像机,在后处理父类中加入如下代码:

private Camera mCamera;
public Camera Camera
{get{if (null == mCamera) mCamera = gameObject.GetComponent<Camera>();return mCamera;}
}

另外,在进行运动模糊的后处理子类脚本中,还需要设置摄像机的深度纹理模式:

private void OnEnable()
{Camera.depthTextureMode |= DepthTextureMode.Depth;
}

测试脚本

using UnityEngine;public class PostEffect_MotionBlur_NDC : PostEffectBase
{public Shader MotionBlurShader_NDC;public Material MotionBlurMat_NDC;[Range(0, 1)]public float BlurSize;[Range(1, 4)]public int BlurRound;private Matrix4x4 mPreviousVP;private void OnEnable(){Camera.depthTextureMode |= DepthTextureMode.Depth;}private void OnRenderImage(RenderTexture src, RenderTexture dest){Material _mat = CheckShaderAndMaterial(MotionBlurShader_NDC, MotionBlurMat_NDC);if(null == _mat) Graphics.Blit(src, dest);else{_mat.SetFloat("_BlurRound", BlurRound);_mat.SetFloat("_BlurSize", BlurSize);_mat.SetMatrix("_PreviousVP", mPreviousVP);Matrix4x4 _curVP = Camera.projectionMatrix * Camera.worldToCameraMatrix;_mat.SetMatrix("_InversVP", _curVP.inverse);mPreviousVP = _curVP;Graphics.Blit(src, dest, _mat);}}
}

测试Shader:

Shader "MyShader/Chapter_13/Chapter_13_MotionBlur_NDC_Shader"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{ZTest Always ZWrite Off Cull OffPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;float4 uv : TEXCOORD0;};sampler2D _MainTex;float4 _MainTex_TexelSize;sampler2D _CameraDepthTexture;float4x4 _InversVP;float4x4 _PreviousVP;half _BlurRound;half _BlurSize;v2f vert(appdata_img v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = v.texcoord;o.uv.zw = v.texcoord;#if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0)o.uv.w = 1 - o.uv.w;#endifreturn o;}fixed4 frag(v2f i) : SV_Target{fixed _d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.zw);fixed4 _curNDC = fixed4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, _d * 2 - 1, 1);float4 _worldPos = mul(_InversVP, _curNDC);_worldPos /= _worldPos.w;float4 _preNDC = mul(_PreviousVP, _worldPos);_preNDC /= _preNDC.w;float2 _velocity = (_curNDC.xy - _preNDC.xy) * 0.5;float2 _uv = i.uv.xy;float4 _color = tex2D(_MainTex, i.uv);for(int it = 1; it < _BlurRound; it++){_uv += _velocity * _BlurSize;_color += tex2D(_MainTex, _uv);}_color /= _BlurRound;return fixed4(_color.rgb, 1);}ENDCG}}
}

测试效果:
在这里插入图片描述

2. 全局雾效

2.1 Unity内置雾效

Unity内置的雾效可以产生基于距离的线性或指数的雾效,如果在自己编写的Shader中支持雾效,需要在Shader中添加#pragma multi_compile_fog编译指令,同时,在Shader中还要通过 UNITY_FOG_COORDS、UNITY_TRANSFER_FOG、UNITY_APPLY_FOG 宏计算雾效效果(过程与阴影一致,就不演示了)。

这种雾效的缺点主要有两个:

  • 需要在每个Shader中手动添加代码,不方便修改
  • 这种雾效的实现是固定的,无法定制效果,比如无法实现基于高度的雾效。

2.2 使用深度纹理实现高度雾

下面的例子我们通过深度纹理实现一种基于高度的全局无效,通过深度纹理重建每个像素的世界坐标,本次重建世界坐标使用的方法为射线插值,原理在【Unity Shader入门精要 第13章】使用深度和法线纹理(一)中也有介绍,然后根据高度控制雾的浓度,将原始颜色与雾的颜色进行混合。

测试脚本:

using UnityEngine;public class PostEffect_HeightFog : PostEffectBase
{public Shader HeightFogShader;public Material HeightFogMat;public float FogBottom;public float FogTop;public float FogDensity;public Color FogColor;private Matrix4x4 mFrustumCornerRays;/// <summary>/// 计算纹理四个顶点的射线/// </summary>private void FillFrustumCornerRays(){//HalfHeight = | ToTop | = Near * Tangent(Fov / 2)//ToTop = Camera.Up * HalfHeight //ToRight = Camera.Right * HalfHeight  * aspectfloat _halfHeight = Camera.nearClipPlane * Mathf.Tan(Camera.fieldOfView * 0.5f * Mathf.Deg2Rad);Vector3 _toTop = Camera.transform.up * _halfHeight;Vector3 _toRight = Camera.transform.right * _halfHeight * Camera.aspect;//Scale = 1 / Near//Scaled_O_LD = ( Camera.Forward * Near - ToRight - ToTop ) * Scale//Scaled_O_RD = ( Camera.Forward * Near + ToRight - ToTop ) * Scale//Scaled_O_RU = ( Camera.Forward * Near + ToRight + ToTop ) * Scale//Scaled_O_LU = ( Camera.Forward * Near - ToRight + ToTop ) * ScaleVector3 _forwardVec = Camera.transform.forward * Camera.nearClipPlane;float _scale = 1 / Camera.nearClipPlane;mFrustumCornerRays.SetRow(0, (_forwardVec - _toRight - _toTop) * _scale); //左下mFrustumCornerRays.SetRow(1, (_forwardVec + _toRight - _toTop) * _scale); //右下mFrustumCornerRays.SetRow(2, (_forwardVec + _toRight + _toTop) * _scale); //右上mFrustumCornerRays.SetRow(3, (_forwardVec - _toRight + _toTop) * _scale); //左上}private void OnRenderImage(RenderTexture src, RenderTexture dest){Material _mat = CheckShaderAndMaterial(HeightFogShader, HeightFogMat);if (null == _mat) Graphics.Blit(src, dest);else{_mat.SetFloat("_FogBottom", FogBottom);_mat.SetFloat("_FogTop", FogTop);_mat.SetFloat("_FogDensity", FogDensity);_mat.SetColor("_FogColor", FogColor);FillFrustumCornerRays();_mat.SetMatrix("_FrustumCornersRay", mFrustumCornerRays);Graphics.Blit(src, dest, _mat);}}
}

测试Shader:

Shader "MyShader/Chapter_13/Chapter_13_HeightFog_Shader"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{ZTest Always ZWrite Off Cull OffPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;float4 uv : TEXCOORD0;float3 scaledRay : TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_TexelSize;sampler2D _CameraDepthTexture;float4x4 _FrustumCornersRay;float _FogBottom;float _FogTop;float _FogDensity;fixed4 _FogColor;v2f vert(appdata_img v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = v.texcoord;o.uv.zw = v.texcoord;#if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0)o.uv.w = 1 - o.uv.w;#endif//判断当前处理的是四个顶点中的哪一个//然后选择对应的射线放入插值寄存器int _index;if(o.uv.x < 0.5 && o.uv.y < 0.5)_index = 0; //左下else if(o.uv.x > 0.5 && o.uv.y < 0.5)_index = 1; //右下else if(o.uv.x > 0.5 && o.uv.y > 0.5)_index = 2; //右上else_index = 3; //左上#if UNITY_UV_STARTS_AT_TOPif (_MainTex_TexelSize.y < 0)_index = 3 - _index;#endifo.scaledRay = _FrustumCornersRay[_index];return o;}fixed4 frag(v2f i) : SV_Target{fixed4 _samplerColor = tex2D(_MainTex, i.uv.xy);fixed _d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.zw);float _linearEyeDepth = LinearEyeDepth(_d);float3 _worldPos = _WorldSpaceCameraPos.xyz + i.scaledRay.xyz * _linearEyeDepth;float _ratio = (_FogTop - _worldPos.y) / (_FogTop - _FogBottom);float _fogDensity = saturate(_ratio * _FogDensity);fixed4 _finalColor = lerp(_samplerColor, _FogColor, _fogDensity);return fixed4(_finalColor.rgb, 1);}ENDCG}}
}

测试效果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/849647.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LAMPSECURITY: CTF4 靶机实战

信息收集&#xff1a; 存活扫描&#xff1a; 端口扫描&#xff1a; 服务扫描&#xff1a; web页面&#xff1a; blog页面发现注入点&#xff1a; sql注入&#xff1a; sqlmap一把梭&#xff1a; 多个参数记得打&#xff1a; 哦 ssh登录&#xff1a; 老版本的ssh&#xff0c;…

Redis高频面试基本问题整理

文章目录 1、Redis底层协议2、Redis的热Key问题如何解决3、Redis是单线程还是多线程4、 什么是脑裂问题&#xff1f;5、redis集群会有写操作丢失吗&#xff1f;6、什么是 Redis 的 Pipeline&#xff1f;它有哪些优点&#xff1f;7、redis主从复制、哨兵机制、集群的理解8、缓存…

浏览器中的disable cache对文件下载服务的影响

客户端缓存文件 对于HTTP的文件请求来说&#xff0c;为了保证请求的速度&#xff0c;会使用客户端缓存的机制。比如客户端向服务器端请求一个文件A.txt。服务器在接收到该请求之后会将A.txt文件发送给客户端。 其请求流程如下&#xff1a; 步骤1&#xff1a;客户端请求服务器…

告别鼠标:蓝牙无线安卓模拟鼠标,绘图板,手写板操作电脑PC端,卡卡罗特也说好,儿童节快乐

家人们&#xff0c;上链接了&#xff1a;https://download.csdn.net/download/jasonhongcn/89387887 横屏模式&#xff1a; 竖屏模式&#xff1a; 操作说明&#xff1a; 1. 手势滑动模拟鼠标移动 2. 界面如果有滚动条&#xff0c;右手指按紧&#xff0c;通过左手指移动实现…

2024年自然语言处理科学与信息检索技术国际会议(ICNLPSIRT 2024)

2024年自然语言处理科学与信息检索技术国际会议(ICNLPSIRT 2024) 2024 International Conference on Natural Language Processing Science and Information Retrieval Technology (ICNLPSIRT 2024) 会议地点&#xff1a;武汉&#xff0c;中国 网址&#xff1a;http://www.i…

使用el-tree封装一个权限管理的小功能

使用el-tree封装一个权限管理的小功能 使用el-tree封装权限管理, 选中人员并且在右侧回显, 此组件用到了递归, 我只是将需要显示的数据进行了动态传递, 其他数据小伙伴可以自己封装 父组件 <template><div><authorityManage ref"authorityManage" :…

python - DataFrame查询数据操作

学习目标 掌握获取df一列或多列数据的方法 知道loc和iloc的区别以及使用方法 知道df的query函数的使用方法 知道isin函数的作用和使用方法 获取DataFrame子集的基本方法 1.1 从前从后获取多行数据 案例中用到的数据集在文章顶部 LJdata.csv 前景回顾 head() & tail(…

实现树形结构几种方式

1&#xff0c;三级分类树形结构查询 /*** DDD(Domain-Driven Design): 领域驱动设计** 三级分类树形结构&#xff1b;* 支持无限层级&#xff1b;* 当前项目只有三级*/ Data public class CategoryTreeTo {private Long categoryId; //1private String categoryName;private …

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(四)---- C语言与计算机架构(Programming xv6 in C)

系列文章目录 操作系统入门系列-MIT6.S081&#xff08;操作系统&#xff09;学习笔记&#xff08;一&#xff09;---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828&#xff08;操作系统工程&#xff09;学习笔记&#xff08;二&#xff09;----课程实验环境搭建&#x…

linux系统——route路由命令

route路由对linux内的ip路由表进行操作 计算机间的数据通信是通过网络来实现的&#xff0c;路由就是从源主机到目标主机的转发过程 路由分为静态路由与动态路由&#xff0c;linux中的均为静态路由&#xff0c;动态路由由交换机路由器自动分配规则而来

[word] word悬挂缩进怎么设置? #经验分享#职场发展#经验分享

word悬挂缩进怎么设置&#xff1f; 在编辑Word的时候上方会有个Word标尺&#xff0c;相信很多伙伴都没使用过。其实它隐藏着很多好用的功能&#xff0c;今天就给大家分享下利用这个word标尺的悬挂缩进怎么设置&#xff0c;一起来看看吧&#xff01; 1、悬挂缩进 选中全文&…

Linux Mint 默认禁用未经验证的 Flatpak 软件包

Linux Mint 默认禁用未经验证的 Flatpak 软件包 Linux Mint 新政策 Linux Mint 项目宣布了一项新政策&#xff0c;即默认禁用那些未经官方验证的 Flatpak 软件包&#xff0c;以增强用户的安全保障。 当用户选择启用未经验证的 Flatpak 软件包时&#xff0c;Linux Mint 的软…

JAVA开发的一套(智造制造领航者云MES系统成品源码)saas云MES制造执行系统源码,全套源码,支持二次开发

JAVA开发的一套&#xff08;智造制造领航者云MES系统成品源码&#xff09;saas云MES制造执行系统源码&#xff0c;全套源码&#xff0c;支持二次开发 1990年11月&#xff0c;美国先进制造研究中心AMR&#xff08;Advanced Manufacturing Research&#xff09;就提出了MES&#…

Linux守护进程揭秘-无声无息运行在后台

在Linux系统中&#xff0c;有一些特殊的进程悄无声息地运行在后台&#xff0c;如同坚实的基石支撑着整个系统的运转。它们就是众所周知的守护进程(Daemon)。本文将为你揭开守护进程的神秘面纱&#xff0c;探讨它们的本质特征、创建过程&#xff0c;以及如何重定向它们的输入输出…

国产主流软硬件厂商生态分析

国产领域主流厂商汇总 信创&#xff0c;即信息技术应用创新&#xff0c;由“信息技术应用创新工作委员会”于2016年3月4日发起&#xff0c;是专注于软硬件关键技术研发、应用与服务的非营利性组织。作为科技自强的关键力量&#xff0c;信创在我国信息化建设中占据核心地位&…

外部mysql导入

利用这个命令&#xff1a; mysql -u username -p database_name < file.sql 然后就这样。成功导入。

定个小目标之每天刷LeetCode热题(12)

这是一道简单题&#xff0c;使用位运算中的异或运算即可&#xff0c;异或运算有以下性质&#xff1a; 1、任何数异或 0 结果仍然是原来的数&#xff0c;即 a⊕0a 2、任何数和其自身做异或运算&#xff0c;结果是 0 所以我们只需要让数组里的所有元素进行异或运算得到的结果就…

探索风电机组:关键软件工具全解析

探索风电机组&#xff1a;关键软件工具全解析 随着可再生能源市场的迅猛发展&#xff0c;风电作为一种重要的可再生能源&#xff0c;其相关技术和工具也越来越受到重视。风电机组的设计、仿真、优化及运维等方面&#xff0c;都需要依靠一系列专业软件工具来实现。这些软件涵盖…

Netty中的ByteBuf使用介绍

ByteBuf有三类&#xff1a; 堆缓存区&#xff1a;JVM堆内存分配直接缓冲区&#xff1a;有计算机内存分配&#xff0c;JVM只是保留分配内存的地址信息&#xff0c;相对于堆内存方式较为昂贵&#xff1b;复合缓冲区&#xff1a;复合缓冲区CompositeByteBuf&#xff0c;它为多个B…

VS2019创建c++动态链接库dll与调用方法

VS2019创建c动态链接库dll与调用方法 1.点击文件-》新建-》项目&#xff0c;输入dll,选择具有导出项的(DLL)动态链接库 2.输入一个文件名&#xff1a;dll2 头文件.h 3.添加加减法函数&#xff1a; // 下列 ifdef 块是创建使从 DLL 导出更简单的 // 宏的标准方法。此 DLL 中的…