您需要 登录 才可以下载或查看,没有账号?注册
x
【已获得授权转载】
承接上文:(上)Unity5新版Shader模板源码解析&运动模糊屏幕特效的实现 (注意。原本叫长。为方便观看。特分上下篇幅。)
三、运动模糊屏幕特效的实现
关于运动模糊特效,如果把握要要点的话,实现起来其实比较简单,就是一个脚本文件配合一个Shader,便可以实现较为出色的运动模糊特效。而其中的脚本文件用于控制Shader中的外部参数。
也就是说一个屏幕特效通常分为两部分来实现:
Shader实现部分
脚本实现部分
下面我们对运动模糊屏幕特效的实现分别进行简单的描述。
可以点击这里跳转到Github,查看详细注释好的运动模糊屏幕特效的实现源码。
3.1 Shader实现部分
先看一下Shader代码的写法,因为基本上已经逐行注释,就不花时间和笔墨仔细讲解了,详细注释的代码如下:
可以发现,这是一个单子着色器、单通道的顶点&片段着色器,顶点着色函数vert中基本上都是写的比较中规中矩的代码,精髓之处在于片段着色器frag中,用一个for
循环,将像素颜色按照一条直线(uv * scale + center)进行了迭代采样累加,最终将采样的颜色的总和除以采样次数,得到了想要实现的运动模糊效果。
3.2 脚本实现部分
脚本文件的实现方面,如下的即个点是要提出来专门讲一下的,即Shader文件的获取方法和OnRenderImage函数、Blit函数。
3.2.1 Shader文件的获取
Shader文件的获取可以使用Shader.Find函数实现。需要注意,Shader.Find函数参数应该和Shader代码中的名称一致,
也就是下面的代码框架中xxx的值,而不是Shader的文件名:
举个例子,脚本代码如果是这样:
- CurShader = Shader.Find ("浅墨Shader编程/Volume8/运动模糊特效标准版");
点击此处复制文本
那么获取到的Shader,文件名是任意的,但Shader代码框架肯定是这样:
- Shader "浅墨Shader编程/Volume8/运动模糊特效标准版"
- {
- ……
- }
点击此处复制文本
3.2.2 OnRenderImage函数与Blit函数
OnRenderImage()函数是MonoBehaviour中提供的一个可供我们重写的函数,它在unity完成所有图片的渲染后被调用。所以我们想实现屏幕特效,主要依靠它来实现。而OnRenderImage函数的函数原型是:
- void OnRenderImage(RenderTexture sourceTexture,RenderTexture destTexture);
点击此处复制文本 另外,我们需要配合一个Graphics.Blit函数,实现从源纹理到目标渲染纹理的拷贝过程,其原型如下三种:
- public static void Blit(Texture source,RenderTexture dest);
- public static void Blit(Texture source,RenderTexture dest, Material mat, int pass = -1);
- public static void Blit(Texture source,Material mat, int pass = -1);
点击此处复制文本 其中。
第一个参数,Texture类型的source,原始纹理。
第二个参数,RenderTexture类型的dest,目标渲染纹理,若为null,表示直接将原始纹理拷贝到屏幕之上。
第三个参数,Material类型的mat,使用的材质(其实也就是Shader),根据不同材质的准备,就是在这里实现后期的效果的。
第四个参数,int类型的pass,有默认值 -1,表示使用所有的pass。用于指定使用哪一个pass。
说个题外话,其实在很久之前的Win32 API游戏编程中,同样原理和相似用途的Blit函数用得太多了。
好的,最后看一下实现屏幕特效的核心代码,如下:
- void OnRenderImage(RenderTexture sourceTexture, RenderTexturedestTexture)
- {
- //着色器实例不为空,就进行参数设置
- if (CurShader != null)
- {
- //设置Shader中的外部变量
- material.SetFloat("_IterationNumber", IterationNumber);
- material.SetFloat("_Value", Intensity);
- material.SetFloat("_Value2", OffsetX);
- material.SetFloat("_Value3", OffsetY);
- material.SetFloat("_Value4", blurWidth);
- material.SetVector("_ScreenResolution", new Vector4(sourceTexture.width, sourceTexture.height, 0.0f, 0.0f));
-
- //拷贝源纹理到目标渲染纹理,加上我们的材质效果
- Graphics.Blit(sourceTexture, destTexture, material);
- }
- //着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的
- else
- {
- //直接拷贝源纹理到目标渲染纹理
- Graphics.Blit(sourceTexture, destTexture);
- }
点击此处复制文本
最后看一下详细注释后的脚本完整实现代码:
- using UnityEngine;using System.Collections;
-
- [ExecuteInEditMode]
-
- public class MotionBlurEffects : MonoBehaviour
- {
-
- //-------------------变量声明部分-------------------
- #region Variables
- public Shader CurShader;//着色器实例
- private Vector4 ScreenResolution;//屏幕分辨率
- private Material CurMaterial;//当前的材质
-
- [Range(5, 50)]
- public float IterationNumber = 15;
- [Range(-0.5f, 0.5f)]
- public float Intensity = 0.125f;
- [Range(-2f, 2f)]
- public float OffsetX = 0.5f;
- [Range(-2f, 2f)]
- public float OffsetY = 0.5f;
-
-
- public static float ChangeValue;
- public static float ChangeValue2;
- public static float ChangeValue3;
- public static float ChangeValue4;
- #endregion
-
-
- //-------------------------材质的get&set----------------------------
- #region MaterialGetAndSet
- Material material
- {
- get
- {
- if (CurMaterial == null)
- {
- CurMaterial = new Material(CurShader);
- CurMaterial.hideFlags = HideFlags.HideAndDontSave;
- }
- return CurMaterial;
- }
- }
- #endregion
-
- //-----------------------------------------【Start()函数】---------------------------------------------
- // 说明:此函数仅在Update函数第一次被调用前被调用
- //--------------------------------------------------------------------------------------------------------
- void Start()
- {
- //依此赋值
- ChangeValue = Intensity;
- ChangeValue2 = OffsetX;
- ChangeValue3 = OffsetY;
- ChangeValue4 = IterationNumber;
-
- //找到当前的Shader文件
- CurShader = Shader.Find("浅墨Shader编程/Volume8/运动模糊特效标准版");
-
- //判断是否支持屏幕特效
- if (!SystemInfo.supportsImageEffects)
- {
- enabled = false;
- return;
- }
- }
-
- //-------------------------------------【OnRenderImage()函数】------------------------------------
- // 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果
- //--------------------------------------------------------------------------------------------------------
- void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
- {
- //着色器实例不为空,就进行参数设置
- if (CurShader != null)
- {
- //设置Shader中的外部变量
- material.SetFloat("_IterationNumber", IterationNumber);
- material.SetFloat("_Value", Intensity);
- material.SetFloat("_Value2", OffsetX);
- material.SetFloat("_Value3", OffsetY);
- material.SetVector("_ScreenResolution", new Vector4(sourceTexture.width, sourceTexture.height, 0.0f, 0.0f));
-
- //拷贝源纹理到目标渲染纹理,加上我们的材质效果
- Graphics.Blit(sourceTexture, destTexture, material);
- }
- //着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的
- else
- {
- //直接拷贝源纹理到目标渲染纹理
- Graphics.Blit(sourceTexture, destTexture);
- }
-
- }
-
-
- //-----------------------------------------【OnValidate()函数】--------------------------------------
- // 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用
- //--------------------------------------------------------------------------------------------------------
- void OnValidate()
- {
- //将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效
- ChangeValue4 = IterationNumber;
- ChangeValue = Intensity;
- ChangeValue2 = OffsetX;
- ChangeValue3 = OffsetY;
-
- }
-
- //-----------------------------------------【Update()函数】------------------------------------------
- // 说明:此函数在每一帧中都会被调用
- //--------------------------------------------------------------------------------------------------------
- void Update()
- {
- if (Application.isPlaying)
- {
- //赋值
- IterationNumber = ChangeValue4;
- Intensity = ChangeValue;
- OffsetX = ChangeValue2;
- OffsetY = ChangeValue3;
-
- }
-
- //找到对应的Shader文件
- #if UNITY_EDITOR
- if (Application.isPlaying != true)
- {
- CurShader = Shader.Find("浅墨Shader编程/Volume8/运动模糊特效标准版");
-
- }
- #endif
- }
-
-
- //-----------------------------------------【OnDisable()函数】---------------------------------------
- // 说明:当对象变为不可用或非激活状态时此函数便被调用
- //--------------------------------------------------------------------------------------------------------
- void OnDisable()
- {
- if (CurMaterial)
- {
- DestroyImmediate(CurMaterial);
- }
- }
- }
点击此处复制文本
3.3 关于如何使用此特效
使用方面的话比较简单,把脚本文件拖到主摄像机上面,效果就出来了
脚本文件中有如下这些参数可以调整,得到不同的模糊效果:
Iteration - Number 迭代次数
Intensity - 模糊强度
Offset X - X方向上的偏移
Offset Y - Y方向上的偏移
四、最终的效果展示
这边贴几张场景的效果图和使用了屏幕特效后的效果图。需要注意的是,本次的场景效果,除了类似CS/CF的FPS游戏的控制系统以外,
还可以使用键盘上的按键【F】,开启或者关闭运动模糊特效。正如下图所展示的:
下面是场景实例运行的截图:
五、后记
本来准备这次更新再稍微剖析一下Unity5中主推的Standard Shader的写法思路的,但发现这篇博文的篇幅已经有点长了,那么,StandardShader就留到下次更新再讲。
本次的更新大致如此,以后的更新依然是安排在每周一,最近一段时间尽量保证每周都更。
最后,感谢各位捧场,我们下周再见。
附: 本文相关下载链接清单回复可见:
尊敬的 游客,如果您要查看本帖关注 或 回复可见内容请 关注或 回复后刷新页面查看!
本系列文章由@浅墨_毛星云 出品
文章链接: http://blog.csdn.net/poem_qianmo/article/details/49405909
作者:毛星云(浅墨) 微博:http://weibo.com/u/1723155442
|