【Unity Shader入门精要 第12章】屏幕后处理效果(三)

1. Bloom效果

Bloom描述的是图像中较亮的部分向周围一定范围内发生扩散,造成一种朦胧的效果,常用于表现游戏中的灯光或隧道出口之类的效果。

下面的例子将实现一个简单的Bloom效果,其原理是:

  • 将原始图像中较亮(灰度值超过阈值)的部分提取出来,存储到一张临时纹理上
  • 对提取出来的亮部做高斯模糊,使图像发散
  • 将高斯模糊过的亮部与原始图像进行叠加

这里我们第一次涉及到图像翻转的问题:由于OpenGL平台和DX平台对屏幕空间的Y轴方向定义是相反的,而Unity的渲染底层是基于OpenGL标准,因此我们在Unity中抓取的屏幕图像,在DX平台上直接使用就存在上下颠倒的问题。为了避免这种情况,在大部分情况下Unity会在Graphics.Blit时自动进行翻转,但像本次Bloom效果这种,在Blit中需要对多张纹理进行采样时,就需要我们手动进行翻转

#if UNITY_UV_STARTS_AT_TOPif(_MainTex_TexelSize.y < 0)o.uv.w = 1 - o.uv.w;
#endif

测试脚本

using UnityEngine;public class PostEffect_Bloom : PostEffectBase
{public Shader BloomShader;public Material BlooMaterial;[Range(0.0f, 1.0f)]public float BrightThreshold = 0.5f;[Range(1, 8)]public int DowmSampler = 4;[Range(0.1f, 3.0f)]public float SmaplerStep = 1;[Range(1, 8)]public int BlurRound = 1;private void OnRenderImage(RenderTexture src, RenderTexture dest){Material _mat = CheckShaderAndMaterial(BloomShader, BlooMaterial);if (null == _mat) Graphics.Blit(src, dest);else{_mat.SetFloat("_BrightThreshold", BrightThreshold);int _width = src.width / DowmSampler;int _height = src.height / DowmSampler;RenderTexture _buffer_0 = RenderTexture.GetTemporary(_width, _height, 0);_buffer_0.filterMode = FilterMode.Bilinear;//用第一个Pass将亮部提取出来Graphics.Blit(src, _buffer_0, _mat, 0);for (int i = 0; i < BlurRound; i++){_mat.SetFloat("_SmaplerStep", i * SmaplerStep);//使用第二个Pass横向滤波RenderTexture _buffer_1 = RenderTexture.GetTemporary(_width, _height, 0);Graphics.Blit(_buffer_0, _buffer_1, _mat, 1);RenderTexture.ReleaseTemporary(_buffer_0);_buffer_0 = _buffer_1;//使用第三个Pass纵向滤波_buffer_1 = RenderTexture.GetTemporary(_width, _height, 0);Graphics.Blit(_buffer_0, _buffer_1, _mat, 2);RenderTexture.ReleaseTemporary(_buffer_0);_buffer_0 = _buffer_1;}//使用第四个Pass将处理后的亮部与原始图像混合_mat.SetTexture("_BloomTex", _buffer_0);Graphics.Blit(src, dest, _mat, 3);RenderTexture.ReleaseTemporary(_buffer_0);Graphics.Blit(src, dest, _mat);}}
}

测试Shader

Shader "MyShader/Chapter_12/Chapter_12_Bloom_Shader"
{Properties{_MainTex("MainTex", 2D) = "white"{}}SubShader{ZTest Always ZWrite Off Cull OffCGINCLUDE#include "UnityCG.cginc"sampler2D _MainTex;float4 _MainTex_TexelSize;fixed _BrightThreshold;sampler2D _BloomTex;half _SmaplerStep;struct v2f_ExtractBright{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f_ExtractBright vert_ExtractBright(appdata_img v){v2f_ExtractBright o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;return o;}fixed Luminance(fixed4 _color){return 0.2125 * _color.r + 0.7154 * _color.g + 0.0721 * _color.b;}fixed4 frag_ExtractBright(v2f_ExtractBright i) : SV_Target{fixed4 _samplerColor = tex2D(_MainTex, i.uv);fixed _fixValue = clamp(Luminance(_samplerColor) - _BrightThreshold, 0, 1);return _samplerColor * _fixValue;}struct v2f_Mix{float4 pos : SV_POSITION;float4 uv : TEXCOORD0;};v2f_Mix vert_Mix(appdata_img v){v2f_Mix o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = v.texcoord;o.uv.zw = v.texcoord;#if UNITY_UV_STARTS_AT_TOPif(_MainTex_TexelSize.y < 0)o.uv.w = 1 - o.uv.w;#endifreturn o;}fixed4 frag_Mix(v2f_Mix i) : SV_Target{return tex2D(_MainTex, i.uv.xy) + tex2D(_BloomTex, i.uv.zw);}ENDCGPass{CGPROGRAM#pragma vertex vert_ExtractBright#pragma fragment frag_ExtractBright   ENDCG}//调用已有的高斯模糊PASSUsePass "MyShader/Chapter_12/Chapter_12_GaussianBlur_Shader/GAUSSIAN_BLUR_HORIZENTAL"UsePass "MyShader/Chapter_12/Chapter_12_GaussianBlur_Shader/GAUSSIAN_BLUR_VERTICAL"Pass{CGPROGRAM#pragma vertex vert_Mix#pragma fragment frag_Mix   ENDCG}}
}

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

2. 运动模糊

运动模糊的原理是,当物体发生位置变化时,前后帧的影像发生叠加,造成模糊的效果。通过运动模糊可以更好的表现速度感。

下面的例子将通过累积缓存的方式实现一个运动模糊的效果:

  • 创建一张临时纹理,用于记录已经渲染过的图像,即过去帧的影像
  • 设置过去帧的混合系数(MixAmount),用于控制过去帧的模糊影像的清晰程度
  • 在第一个 Pass 中将当前帧的影像与保存的过去帧图像进行混合,混合系数为(1 - 过去帧的 MixAmount),这一步的目的只是为了在同一张图片上能够同时表现出物体在不同时刻的位置,因此我们只需要表现物体颜色的 RGB 部分,而并不希望混合时也改变 Alpha 值,这里可以通过 ColorMask RGB 实现只写入 RGB 通道的值
  • 最终渲染图像的 Alpha 值应以当前帧的实际 Alpha 值为准,因此在第二个 Pass 中再次对当前帧原始图像进行采样,通过 Color Mask A 只将Alpha值写入

测试脚本

using UnityEngine;public class PostEffect_MotionBlur : PostEffectBase
{public Shader MotionBlurShader;public Material MotionBlurMat;/// <summary>/// 已渲染图像在混合中的权重/// </summary>[Range(0, 1)]public float PreviousAmount = 0.5f;//用于记录已经渲染的图像private RenderTexture mAccRT;private void OnRenderImage(RenderTexture src, RenderTexture dest){Material _mat = CheckShaderAndMaterial(MotionBlurShader, MotionBlurMat);if(null == _mat) Graphics.Blit(src, dest);else{CheckAccRT(src.width, src.height);_mat.SetFloat("_MixAmount", 1 - PreviousAmount);//调用 Shader 进行混合//先将结果混合到 AccRT 中,用于保存结果给下一帧使用Graphics.Blit(src, mAccRT, _mat);//再将混合结果输出Graphics.Blit(mAccRT, dest);}}/// <summary>/// 检测当前 AccRT 是否已创建以及是否与本帧尺寸一致/// </summary>/// <param name="_width"></param>/// <param name="_height"></param>private void CheckAccRT(int _width, int _height){if (null == mAccRT || _width != mAccRT.width || _height != mAccRT.height){DestroyImmediate(mAccRT);mAccRT = new RenderTexture(_width, _height, 0);mAccRT.hideFlags = HideFlags.HideAndDontSave;}}private void OnDestroy(){DestroyImmediate(mAccRT);}
}

测试Shader

Shader "MyShader/Chapter_12/Chapter_12_MotionBlur_Shader"
{Properties{_MainTex("MainTex", 2D) = "white"{}}SubShader{ZTest Always ZWrite Off Cull OffCGINCLUDE#include "UnityCG.cginc"sampler2D _MainTex;fixed _MixAmount;struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert(appdata_img v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;return o;}fixed4 frag_RGB(v2f i) : SV_Target{return fixed4(tex2D(_MainTex, i.uv).rgb, _MixAmount);}fixed4 frag_A(v2f i) : SV_Target{return tex2D(_MainTex, i.uv);}ENDCGPass{Blend SrcAlpha OneMinusSrcAlphaColorMask RGBCGPROGRAM#pragma vertex vert#pragma fragment frag_RGBENDCG}Pass{Blend One ZeroColorMask ACGPROGRAM#pragma vertex vert#pragma fragment frag_AENDCG}}
}

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

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

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

相关文章

2023-2025年最值得选择的Java毕业设计选题大全:1000个热门选题推荐✅✅✅

&#x1f497;博主介绍&#xff1a;✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还…

密码加密及验证

目录 为什么需要加密&#xff1f; 密码算法分类 对称密码算法 非对称密码算法 摘要算法 DigestUtils MD5在线解密工具原理 实现用户密码加密 代码实现 为什么需要加密&#xff1f; 在MySQL数据库中&#xff0c;我们常常需要对用户密码、身份证号、手机号码等敏感信息进…

centos8stream 编译安装 php-rabbit-mq模块

官方GitHub&#xff1a;https://github.com/php-amqp/php-amqp 环境依赖安装 dnf install cmake make -y 1.安装rabbitmq-c cd /usr/local/src/ wget https://github.com/alanxz/rabbitmq-c/archive/refs/tags/v0.14.0.tar.gz tar xvf v0.14.0.tar.gz cd rabbitmq-c-0.14.0/…

NoSQL是什么?NoSQL数据库存在SQL注入攻击?

一、NoSQL是什么&#xff1f; NoSQL&#xff08;Not Only SQL&#xff09;是一种非关系型数据库的概念。与传统的关系型数据库不同&#xff0c;NoSQL数据库使用不同的数据模型来存储和检索数据。NOSQL数据库通常更适合处理大规模的非结构化和半结构化数据&#xff0c;且能够…

Docker-----emqx部署

emqx通过Docker容器化部署流程 1.创建持久化挂载目录 mkdir -p /home/emqx/etc ------挂载emqx的配置文件目录 mkdir -p /home/emqx/data ------挂载emqx的存储目录 mkdir -p /home/emqx/log ------挂载emqx的日志目录 [root home]# mkdir -p /home/emqx/etc [root home]# mkd…

IC芯片晶片固定保护环氧胶有什么优点?

IC芯片晶片固定保护环氧胶有什么优点&#xff1f; IC芯片晶片固定环氧胶在电子设备制造和组装中被广泛使用&#xff0c;主要用于电子封装和芯片固定应用&#xff0c;具有多种显著优点&#xff0c;其主要优点包括但不限于以下几点&#xff1a; 高强度粘接&#xff1a;环氧胶的固…

开源VS闭源:大模型发展路径之争,你站哪一派?

文章目录 引言一、数据隐私1.1开源大模型的数据隐私1.2 闭源大模型的数据隐私1.3 综合考量 二、商业应用2.1 开源大模型的商业应用2.2 闭源大模型的商业应用2.3 商业应用的综合考量 三、社区参与3.1 开源大模型的社区参与3.2 闭源大模型的社区参与3.3 综合考量 结论 引言 在人…

1.JAVA小项目(零钱通)

一、说明 博客内容&#xff1a;B站韩顺平老师的视频&#xff0c;以及代码的整理。此项目分为两个版本&#xff1a; 面向过程思路实现面向对象思路实现 韩老师视频地址&#xff1a;【【零基础 快速学Java】韩顺平 零基础30天学会Java】 https://www.bilibili.com/video/BV1fh4…

Django基础学习(一)

前端开发 目的&#xff1a;开发一个平台(网站)- 前端开发&#xff1a; HTML, CSS,JavaScript- web框架&#xff1a;接收请求并进行处理- MySQL数据库&#xff1a;存储相应的数据1.快速开发网站 pip install flask创建项目并导入flask框架,然后建立网址和函数的对应关系。 fr…

mysql DDL——增删改

简略版&#xff1a; 文字化&#xff1a; 1.对全部字段添加数据&#xff1a;insert into 表名 values (值1&#xff0c;值2&#xff0c;值3...); 2.对指定字段添加数据&#xff1a;insert into 表名 (字段名1&#xff0c;字段名2...) values &#xff08;值1&#xff0c;值2..…

远程桌面连接不上的解决方法?

随着远程办公的兴起&#xff0c;远程桌面连接成为了日常工作中必不可少的工具之一。有时我们可能会遇到无法连接或连接不稳定的情况。本文将介绍一些常见的远程桌面连接问题及其解决方法。 问题一&#xff1a;无法连接远程桌面 当我们尝试连接远程桌面时&#xff0c;有时会遇到…

uniapp 怎么设置凸起的底部tabbar

1. uniapp 怎么设置凸起的底部tabbar 1.1. 方案一系统提供 1.1.1. 使用uniapp官方提供的属性midButton 使用时&#xff0c;list数组须为偶数 &#xff08;1&#xff09;pages.json "tabBar": {"custom": true,"color": "#8F8F94",&q…

树莓派4B 学习笔记3: 系统自动更新时间_测试CSI摄像头_安装OpenCv_4.6(未成功编译源码)_备份树莓派镜像

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本文我只是安装了OpenCv 4.6&#xff0c;但编译源码失败了&#xff01;有关 OpenCv 部分仅做笔记暂存&#xff01; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令…

【记录】打印|用浏览器生成证件照打印PDF,打印在任意尺寸的纸上(简单无损!)

以前我打印证件照的时候&#xff0c;我总是在网上找在线证件照转换或者别的什么。但是我今天突然就琢磨了一下&#xff0c;用 PDF 打印应该也可以直接打印出来&#xff0c;然后就琢磨出来了&#xff0c;这么一条路大家可以参考一下。我觉得比在线转换成一张 a4 纸要方便的多&am…

基于PHP+MySQL组合开发的720VR全景小程序源码系统 一键生成三维实景 前后端分离带网站的安装代码包以及搭建教程

系统概述 这款源码系统是专门为实现 720VR 全景展示而设计的。它结合了先进的技术和创新的理念&#xff0c;能够将真实场景以全景的形式呈现给用户&#xff0c;让用户仿佛身临其境。该系统采用 PHP 进行后端开发&#xff0c;MySQL 作为数据库管理系统&#xff0c;确保了系统的…

SAP PP学习笔记14 - MTS(Make-to-Stock) 按库存生产(策略10),以及生产计划的概要

上面讲了SAP里面的基础知识&#xff0c;BOM&#xff0c;作业手顺&#xff08;工艺路线&#xff09;&#xff0c;作业区&#xff08;工作中心&#xff09;&#xff0c;MRP&#xff0c;MPS等概念&#xff0c;现在该到用的时候了。 SAP PP学习笔记07 - 简单BOM&#xff0c;派生BO…

17、Spring系列-SpringMVC-请求源码流程

前言 Spring官网的MVC模块介绍&#xff1a; Spring Web MVC是基于Servlet API构建的原始Web框架&#xff0c;从一开始就已包含在Spring框架中。正式名称“ Spring Web MVC”来自其源模块的名称&#xff08;spring-webmvc&#xff09;&#xff0c;但它通常被称为“ Spring MVC…

【C++奇妙冒险】日期类Date的实现

文章目录 前言日期类Date的接口设计构造函数和打印函数获取日期并判断日期是否合法日期类的大小比较关系<运算符重载 判断小于运算符重载 判断相等<运算符重载 判断小于等于>运算符重载 判断大于> 运算符重载 判断大于等于! 运算符重载 不等于 日期类计算日期天数日…

C++ 的 Tag Dispatching(标签派发) 惯用法

目录 1.概述 2.标准库中的例子 3.使用自己的 Tag Dispatching 3.1.使用 type traits 技术 3.2.使用 Type_2_Type 技术 4.Tag Dispatching的使用场景 5.总结 1.概述 一般重载函数的设计是根据不同的参数决定具体做什么事情&#xff0c;编译器会根据参数匹配的原则确定正确…

数据库之函数、存储过程

函数、存储过程 1.函数 函数&#xff0c;常用于对一个或多个输入参数进行操作&#xff0c;主要目的是返回一个结果值&#xff0c;就是一种方法&#xff0c;在postgre里存放的位置叫function&#xff0c;比如创建一个计算长方面积的函数。 举例&#xff1a;建立一个计算长方形…