运动模糊是真实世界中的摄像机的一种效果。如果在摄像机曝光时,拍摄场景发生了变化,就会产生模糊的画面。

运动模糊的实现有多种方法。一种实现方法是利用一块累积缓存(accumulation buffer )来混合多张连续的图像。当物体快速移动产生多张图像后,我们取它们之间的平均值作为最后的运动模糊图像。然而,这种暴力的方法对性能的消耗很大,因为想要获取多张帧图像往往意味着我们需要在同一帧里渲染多次场景。另一种应用广泛的方法是创建和使用速度缓存(velocity buffer),这个缓存中存储了各个像素当前的运动速度,然后利用该值来决定模糊的方向和大小。

在本节中,我们将使用类似上述第一种方法的实现来模拟运动模糊的效果。我们不需要在一帧中把场景渲染多次,但需要保存之前的渲染结果,不断把当前的渲染图像叠加到之前的渲染图像中,从而产生一种运动轨迹的视觉效果。这种方法与原始的利用累计缓存的方法相比性能更好,但模糊效果可能会略有影响。

后处理代码:

using UnityEngine;
using System.Collections;public class MotionBlur : PostEffectsBase {public Shader motionBlurShader;private Material motionBlurMaterial = null;public Material material {  get {motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);return motionBlurMaterial;}  }[Range(0.0f, 0.9f)]public float blurAmount = 0.5f;    //运动模糊参数,值越大,拖尾效果越明显private RenderTexture accumulationTexture;    //保存之前图像叠加的结果void OnDisable() {DestroyImmediate(accumulationTexture);}void OnRenderImage (RenderTexture src, RenderTexture dest) {if (material != null) {// Create the accumulation textureif (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height) {DestroyImmediate(accumulationTexture);accumulationTexture = new RenderTexture(src.width, src.height, 0);accumulationTexture.hideFlags = HideFlags.HideAndDontSave;Graphics.Blit(src, accumulationTexture);}// We are accumulating motion over frames without clear/discard// by design, so silence any performance warnings from UnityaccumulationTexture.MarkRestoreExpected();material.SetFloat("_BlurAmount", 1.0f - blurAmount);Graphics.Blit (src, accumulationTexture, material);Graphics.Blit (accumulationTexture, dest);} else {Graphics.Blit(src, dest);}}
}

在上面的代码里,我们在该脚本不运行时,即调用OnDisable函数时,立即销毁accumulationTexture。这是因为,我们希望在下一次开始应用运动模糊时重新叠加图像。

在确认材质可用后,我们首先判断用于混合图像的accumulationTexture是否满足条件。我们不仅判断它是否为空,还判断它是否与当前的屏幕分辨率相等,如果不满足,就说明我们需要重新创建一个适合于当前分辨率的accumulationTexture变量。创建完毕后,由于我们会自己控制该变量的销毁,因此可以把它的hideFlags设置为HideFlags.HideAndDontSave,这意味着这个变量不会显示在Hierarchy中,也不会保存到场景中。然后,我们使用当前的帧图像初始化accumulationTexture (使用Graphics.Blit(src, accumulationTexture)代码)。

当得到了有效的accumulationTexture 变量后,我们调用了accumulationTexture.MarkRestoreExpected函数来表明我们需要进行一个渲染纹理的恢复操作。恢复操作发生在渲染到纹理而该纹理又没有被提前清空或销毁的情况下。在本例中,我们每次调用OnRenderlmage时都需要把当前的帧图像和accumulationTexture 中的图像混合,accumulationTexture纹理不需要提前清空,因为它保存了我们之前的混合结果。然后,我们将参数传递给材质,并调用Graphics.Blit (src, accumulationTexture, materal)把当前的屏幕图像src叠加到accumulationTexture中。最后使用Graphics.Blit (accumulationTexture, dest)把结果显示到屏幕上。

RenderTexture.MarkRestoreExpected

表示预期将进行 RenderTexture 恢复操作。

在移动图形仿真模式下,当执行 RenderTexture“恢复”操作时,Unity 会发出警告。如果在不先进行清除或丢弃的情况下渲染到纹理,就会执行恢复操作。对于许多移动 GPU 和多 GPU 系统来说,这是一项代价高昂的操作,应该予以避免。

但是,如果渲染效果要求必须进行 RenderTexture 恢复,则您可以调用该函数来指示 Unity 恢复操作是预期行为,不要发出警告。

Shader代码:

Shader "Unity Shaders Book/Chapter 12/Motion Blur" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BlurAmount ("Blur Amount", Float) = 1.0}SubShader {CGINCLUDE#include "UnityCG.cginc"sampler2D _MainTex;fixed _BlurAmount;struct v2f {float4 pos : SV_POSITION;half2 uv : TEXCOORD0;};v2f vert(appdata_img v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;return o;}// 更新渲染纹理的RGB通道部分fixed4 fragRGB (v2f i) : SV_Target {return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount);}// 更新渲染纹理的A通道部分half4 fragA (v2f i) : SV_Target {return tex2D(_MainTex, i.uv);}ENDCGZTest Always Cull Off ZWrite Off// 更新渲染纹理的RGB通道部分Pass {Blend SrcAlpha OneMinusSrcAlphaColorMask RGBCGPROGRAM#pragma vertex vert  #pragma fragment fragRGB  ENDCG}// 更新渲染纹理的A通道部分Pass {   Blend One ZeroColorMask ACGPROGRAM  #pragma vertex vert  #pragma fragment fragAENDCG}}FallBack Off
}

RGB通道版本的Shader对当前图像进行采样,并将其A通道的值设为_BlurAmount, 以便在后面混合时可以使用它的透明通道进行混合。A通道版本的代码就更简单了,直接返回采样结果。实际上,这个版本只是为了维护渲染纹理的透明通道值,不让其受到混合时使用的透明度值的影响。

之所以要把A通道和RGB通道分开,是因为在更新RGB时我们需要设置它的A通道来混合图像,但又不希望A通道的值写入渲染纹理中。

UnityShader入门精要——运动模糊相关推荐

  1. UnityShader入门精要——运动模糊(2)

    本次利用速度映射图方法实现运动模糊.速度映射图中存储了每个像素的速度,然后使用这个速度来决定模糊的方向和大小. 速度缓冲生成的方法: (1)把场景中所有物体的速度渲染到一张纹理中.但这种方法的缺点在于 ...

  2. [学习笔记]UnityShader入门精要_第12章_屏幕后处理效果

    12.2 调整屏幕的亮度,饱和度和对比度 C# CheckShaderAndCreateMaterial Range OnRenderImage Material.SetFloat Graphics ...

  3. 《UnityShader入门精要》总结(1)理论篇

    紫色:大类概念或简短有力的总结 蓝色:细分概念或重要部分 红色:重要的补充注释 第二章:渲染流程与流程分工 渲染的流程分三个阶段: 应用阶段(开发者控制阶段) 由开发者全权进行管理,控制场景内摄像机位 ...

  4. UnityShader入门精要-9

    目录 1. Unity的渲染路径 前向渲染路径 Unity中的前向渲染 延迟渲染 Unity的光源类型 Unity的光照衰减 Unity的阴影 1. Unity的渲染路径 Unity 5.0之前,有3 ...

  5. UnityShader入门精要——全局雾效

    基于屏幕后处理的全局雾效的关键是,根据深度纹理来重建每个像素在世界空间下的位置.我们在模拟运动模糊时已经实现了这个要求,即构建出当前像素的NDC坐标,再通过当前摄像机的视角*投影矩阵的逆矩阵来得到世界 ...

  6. UnityShader入门精要-屏幕后处理效果 亮度饱和度对比度、边缘检测、高斯模糊、bloom效果、运动模糊

    (从这里开始可能会记录的更简略一些,时间紧张想迅速读完这本书的主要内容,可能有的部分不会自己上手做) 屏幕后处理通常指渲染完整个场景得到屏幕图像后,再对图像进行操作,抓取屏幕可以使用OnRenderI ...

  7. UnityShader入门精要-3.3 UnityShader的结构

    一个UnityShader的基础结构如下所示: Shader "ShaderName"{Properties{//属性 } SubShader{//显卡A使用的子着色器 }SubS ...

  8. UnityShader入门精要笔记1——顶点/片元着色器结构与BRDF(基本光照模型)——实现漫反射

    文章目录 BRDF(基本光照模型) 实现漫反射 光线强度的计算 好现在开始写Shader 新建Shader 添加一个Properties语义块 添加SubShader和Pass. 使用CG/HLSL语 ...

  9. UnityShader入门精要——程序纹理

    程序纹理(Procedural Texture)指的是那些由计算机生成的图像,我们通常使用一些特定的算法来创建个性化图案或非常真实的自然元素,例如木头.石子等.使用程序纹理的好处在于我们可以使用各种参 ...

最新文章

  1. Java的基础方法Java的对象_java基础之 创建对象的几种方式
  2. 门户网站建设与运营需要付出更多成本
  3. jsp中session 和 cookies区别
  4. sys.argv[] 的使用详解
  5. ajax参数中有加号,浅谈在js传递参数中含加号(+)的处理方式
  6. 数据库连接和乱码问题
  7. 【IoT平台技术对接分享】如何上传正确的消息推送证书
  8. PG中的几种数据类型转换方式
  9. atom python教程_对于新手来说 如何用atom搭建python的ide?
  10. c# 傅里叶变换 频域_频域(傅里叶变换)有什么用?
  11. 怎么打公式_我们总结了一条抖音爆款公式
  12. div+css,表单和表格 学习笔记
  13. steam一键授权工具_超实用小工具!一键将PC其它平台的游戏导入Steam
  14. 程序员必备 代码比较工具 Beyond Compare 4
  15. win7下修改php.ini的配置路径
  16. 软件设计 抽象_调试抽象给软件工程师带来正念的好处
  17. 微信开发MySQL篇(一)
  18. 深度解析CTM项目成功的原因
  19. 音频单元组件服务参考(Audio Unit Component Services Reference)
  20. Linux 系统安装

热门文章

  1. 新一代亚马逊电子书阅读器Kindle Paperwhite全球同步上市
  2. 100baseT、100baseFX、1000base-SX、100/1000base-T
  3. ubuntu20.04 跳过grub
  4. 一个初中生到程序员的辛酸经历(转载)
  5. 电脑怎么打出冒号符号_冒号的用法有哪些?写作文的时候冒号怎么用?冒号在电脑上怎么打出来?...
  6. java 泛型参数具体类型获取、泛型返回具体类型获取
  7. 使用selenium模仿手机浏览器访问淘宝网页
  8. Linux篇【3】:Linux环境基础开发工具使用(中)
  9. OpenCV 读写图像、读写像素、修改像素值(案例:图像反处理)
  10. 三百英雄服务器维护2020,【梦服】2020年12月3日【版本更新说明】