简介

最近刚刚通关《耻辱2》,在有一关的时候,竟然送给我了一个能够穿越时空的“神器”,有了这货,就可以一下子传送到过去或者回到现在。在使用这个道具的时候,会有一个屏幕扭曲的穿越的效果,感觉效果不错。
在穿越了无数回之后,我终于下决心准备在Unity里面实现一个简化的版本(肯定还原不到这种大作的水平,就当是练习啦,2333)。

屏幕收缩的效果

观察上面的效果图,最明显的一块就是屏幕有一个收缩的效果,这也是这种屏幕扭曲里面最明显也最容易实现的一部分。首先,扭曲效果就是uv偏移,超哪偏移,这个我们可以自己输入一个点给shader,默认就是屏幕中心点。我们让每个采样的点都朝着我们定义的中心点的方向偏移一段距离,就可以实现类似的屏幕收缩的效果。关于扭曲效果的基本知识可以参考一下 屏幕水波纹效果以及 热空气扭曲效果,这里就不多说了。下面附上收缩效果第一版。
c#脚本如下:
/********************************************************************FileName: PassthoughEffect.csDescription: "传说中的穿越"效果Created: 2017/05/07by :puppet_master
*********************************************************************/
using UnityEngine;public class PassthoughEffect : PostEffectBase
{//扭曲强度[Range(0, 0.15f)]public float distortFactor = 1.0f;//扭曲中心(0-1)屏幕空间,默认为中心点public Vector2 distortCenter = new Vector2(0.5f, 0.5f);void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetFloat("_DistortFactor", distortFactor);_Material.SetVector("_DistortCenter", distortCenter);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}
}

shader代码如下:

//屏幕收缩效果
//by:puppet_master
Shader "ApcShader/PaththoughEffect"{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}}CGINCLUDEuniform sampler2D _MainTex;uniform float _DistortFactor;   //扭曲强度uniform float4 _DistortCenter;    //扭曲中心点xy值(0-1)屏幕空间#include "UnityCG.cginc"fixed4 frag(v2f_img i) : SV_Target{//计算偏移的方向float2 dir = i.uv - _DistortCenter.xy;//最终偏移的值:方向 * (1-长度),越靠外偏移越小float2 offset = _DistortFactor * normalize(dir) * (1 - length(dir));//计算采样uv值:正常uv值+从中间向边缘逐渐增加的采样距离float2 uv = i.uv + offset;return tex2D(_MainTex, uv);}ENDCGSubShader {Pass{ZTest AlwaysCull Off ZWrite OffFog { Mode off }//调用CG函数  CGPROGRAM//使效率更高的编译宏#pragma fragmentoption ARB_precision_hint_fastest //vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img#pragma vertex vert_img#pragma fragment frag ENDCG}}
}
找个测试场景,未收缩前的效果如下:
调整扭曲系数后,屏幕朝中心点收缩的效果如下:

屏幕扭曲效果与收缩效果结合

有了屏幕收缩效果,最基本的功能完成了。但是我们观察上面的动态图,还能发现,在马上要“穿越”到另一个场景的时候,屏幕会出现比较强烈的扰动效果,也正好是在这个状态下,进行的场景切换。其实这个状态很重要,切场景就相当于准备演员神马的,还是需要放块幕布之类的遮一下,不然就都现场直播了。我们需要做的就是让屏幕尽可能地扭曲,看不粗来到底发生了什么就好了。
关于扭曲效果,在上一篇文章中已经介绍过原理并且实现过一次,不过这里的扭曲要和上面的屏幕收缩相结合。两者都是uv偏移的原理,这里我选择把两者进行相减操作,首先计算正常屏幕收缩的uv偏移值,这个偏移值一般比较大。然后再计算根据一张噪声图,得到一个小的uv偏移值,作为扰动的uv偏移,两者结合就能够得到最终扭曲+扰动的效果。
c#脚本如下,增加了一个噪声图槽位以及扰动控制系数:
/********************************************************************FileName: PassthoughEffect.csDescription: "传说中的穿越"效果Created: 2017/05/07by :puppet_master
*********************************************************************/
using UnityEngine;public class PassthoughEffect : PostEffectBase
{//收缩强度[Range(0, 0.15f)]public float distortFactor = 1.0f;//扭曲中心(0-1)屏幕空间,默认为中心点public Vector2 distortCenter = new Vector2(0.5f, 0.5f);//噪声图public Texture NoiseTexture = null;//屏幕扰动强度[Range(0, 2.0f)]public float distortStrength = 1.0f;void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortFactor", distortFactor);_Material.SetVector("_DistortCenter", distortCenter);_Material.SetFloat("_DistortStrength", distortStrength);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}
}

shader代码如下:

//屏幕收缩效果
//by:puppet_master
Shader "ApcShader/PaththoughEffect"{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_NoiseTex("Noise", 2D) = "black"{}}CGINCLUDEuniform sampler2D _MainTex;uniform sampler2D _NoiseTex;uniform float _DistortFactor;    //扭曲强度uniform float4 _DistortCenter;    //扭曲中心点xy值(0-1)屏幕空间uniform float _DistortStrength; #include "UnityCG.cginc"fixed4 frag(v2f_img i) : SV_Target{//计算偏移的方向float2 dir = i.uv - _DistortCenter.xy;//最终偏移的值:方向 * (1-长度),越靠外偏移越小float2 scaleOffset = _DistortFactor * normalize(dir) * (1 - length(dir));//采样Noise贴图fixed4 noise = tex2D(_NoiseTex, i.uv);//noise的权重 = 参数 * 距离,越靠近外边的部分,扰动越严重float2 noiseOffset = noise.xy * _DistortStrength * dir;//计算最终offset = 两种扭曲offset的差(取和也行,总之效果好是第一位的)float2 offset = scaleOffset - noiseOffset;//计算采样uv值:正常uv值+从中间向边缘逐渐增加的采样距离float2 uv = i.uv + offset;return tex2D(_MainTex, uv);}ENDCGSubShader {Pass{ZTest AlwaysCull Off ZWrite OffFog { Mode off }//调用CG函数    CGPROGRAM//使效率更高的编译宏#pragma fragmentoption ARB_precision_hint_fastest //vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img#pragma vertex vert_img#pragma fragment frag ENDCG}}
}

还是上面的测试场景,这次,我们用一个噪声图,比如下图所示的这种:

然后设置一下扰动的权重,就可以看到,场景除了朝中心收缩了,还带有了扰动的效果:

动态的收缩和扭曲效果

我们实现了收缩和扭曲的效果。和上面的动图比较的话,除了挫了点,就是不能动了。下面研究下怎么让这个动起来。首先,这种类型的控制,基本就不能再在shader里面做了,我们下面要做的,就是动态改变我们在静态时设置的几个参数。在update或者开一个协程,让收缩系数从0逐渐增加到最大,然后迅速降低为0;在快要结束时,突然增大扰动系数,并执行切换镜头等的操作。
先来看收缩效果,这里呢,我们为了方便调整,直接给一个曲线控制。曲线控制可以得到一些特别好玩的效果,而且可以免去我们写很多麻烦的控制代码,还可以直接把效果参数开放出来,让策划和美术同学根据需要来调整,最主要的是可以顺便偷下懒,2333。还是上面的shader,我们仅仅修改了C#脚本,用一个协程控制采样曲线:
/********************************************************************FileName: PassthoughEffect.csDescription: "传说中的穿越"效果Created: 2017/05/10by :puppet_master
*********************************************************************/
using UnityEngine;
using System.Collections;public class PassthoughEffect : PostEffectBase
{//收缩强度[Range(0, 0.15f)]public float distortFactor = 1.0f;//扭曲中心(0-1)屏幕空间,默认为中心点public Vector2 distortCenter = new Vector2(0.5f, 0.5f);//噪声图public Texture NoiseTexture = null;//屏幕扰动强度[Range(0, 2.0f)]public float distortStrength = 1.0f;//屏幕收缩总时间public float passThoughTime = 4.0f;//当前时间private float currentTime = 0.0f;//曲线控制权重public float curveFactor = 0.2f;//屏幕收缩效果曲线控制public AnimationCurve curve;void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortFactor", distortFactor);_Material.SetVector("_DistortCenter", distortCenter);_Material.SetFloat("_DistortStrength", distortStrength);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}//ContexMenu,可以直接在Component上右键调用该函数,比较好用的小技巧哈[ContextMenu("Play")]public void StartPassThoughEffect(){currentTime = 0.0f;StartCoroutine(UpdatePassthoughEffect());}private IEnumerator UpdatePassthoughEffect(){while(currentTime < passThoughTime){currentTime += Time.deltaTime;//根据时间占比在曲线(0,1)区间采样,再乘以权重作为收缩系数distortFactor = curve.Evaluate(currentTime / passThoughTime) * curveFactor;yield return null;//结束时强行设置为0distortFactor = 0.0f;}}}

然后呢,我们就可以来调整曲线来得到我们希望的效果啦。《耻辱》中的扭曲效果是一个缓慢加大,然后再突然恢复的一个过程,我们用曲线调整一个类似的效果,如下:

得到的效果如下面的动态图所示,基本还原了这种收缩的效果:
下面就是在收缩到最大的时候,给一个比较大的扰动系数,达到转场的目的。尴尬,好不容易调好的曲线,把变量改了个名字,曲线丢掉了...只好重新调一遍。最终版本如下:
/********************************************************************FileName: PassthoughEffect.csDescription: "传说中的穿越"效果Created: 2017/05/10by :puppet_master
*********************************************************************/
using UnityEngine;
using System.Collections;public class PassthoughEffect : PostEffectBase
{//收缩强度[Range(0, 0.15f)]public float distortFactor = 1.0f;//扭曲中心(0-1)屏幕空间,默认为中心点public Vector2 distortCenter = new Vector2(0.5f, 0.5f);//噪声图public Texture NoiseTexture = null;//屏幕扰动强度[Range(0, 2.0f)]public float distortStrength = 1.0f;//屏幕收缩总时间public float passThoughTime = 4.0f;//当前时间private float currentTime = 0.0f;//曲线控制权重public float scaleCurveFactor = 0.2f;//屏幕收缩效果曲线控制public AnimationCurve scaleCurve;//扰动曲线系数public float distortCurveFactor = 1.0f;//屏幕扰动效果曲线控制public AnimationCurve distortCurve;void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortFactor", distortFactor);_Material.SetVector("_DistortCenter", distortCenter);_Material.SetFloat("_DistortStrength", distortStrength);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}//ContexMenu,可以直接在Component上右键调用该函数,比较好用的小技巧哈[ContextMenu("Play")]public void StartPassThoughEffect(){currentTime = 0.0f;StartCoroutine(UpdatePassthoughEffect());}private IEnumerator UpdatePassthoughEffect(){while(currentTime < passThoughTime){currentTime += Time.deltaTime;float t = currentTime / passThoughTime;//根据时间占比在曲线(0,1)区间采样,再乘以权重作为收缩系数distortFactor = scaleCurve.Evaluate(t) * scaleCurveFactor;distortStrength = distortCurve.Evaluate(t) * distortCurveFactor;yield return null;//结束时强行设置为0distortFactor = 0.0f;distortStrength = 0.0f;}}
}

各项参数以及扰动曲线设置如下图所示,噪声图换了一张其他的:

最终效果如下面动图所示:

漩涡扭曲效果

漩涡扭曲效果,本来打算尝试一下卡卡西的“神威”技能效果,不过效果不是很好,所以只实现了一版漩涡扭曲的效果,以后有时间再慢慢研究。说道漩涡类型的东东,第一个想到的应该就是sin,cos函数,这俩跟漩涡非常搭边。然后我们分析一下漩涡的效果,我们先需要在fragment shader中对应每个像素点先平移到中心点(也可以是我们自己定义的中心),然后让这个像素点绕着当前中心点的轴旋转一定角度,最后再将这个像素点平移回去,就能够达到了整个图像绕着固定点旋转的操作。而为了让漩涡效果看起来更加自然,我们需要按照离中心点的距离作为权重,缩放旋转的角度值,离中心点越远的像素点,旋转值越小,而离中心点越近的位置,旋转得就越剧烈,这是一个反比的关系,所以我们在给旋转值的时候,除以一个距离中心点的距离即可。下面附上漩涡扭曲效果的shader以及C#脚本。
Shader部分如下,将扭曲部分改为漩涡形,附加一个噪声扰动的效果:
//漩涡扭曲效果
//by:puppet_master
Shader "ApcShader/RotationDistortEffect"{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_NoiseTex("Noise", 2D) = "black"{}}CGINCLUDEuniform sampler2D _MainTex;uniform sampler2D _NoiseTex;uniform float _DistortFactor;   //扭曲强度uniform float4 _DistortCenter;    //扭曲中心点xy值(0-1)屏幕空间uniform float _DistortStrength; #include "UnityCG.cginc"fixed4 frag(v2f_img i) : SV_Target{//平移坐标点到中心点,同时也是当前像素点到中心的方向fixed2 dir = i.uv - _DistortCenter.xy;//计算旋转的角度:对于像素点来说,距离中心越远,旋转越少,所以除以距离。相当于用DistortFactor作为旋转的角度值Distort/180 * π,π/180 = 0.1745float rot = _DistortFactor * 0.1745 / (length(dir) + 0.001);//+0.001防止除零//计算sin值与cos值,构建旋转矩阵fixed sinval, cosval;sincos(rot, sinval, cosval);float2x2  rotmatrix = float2x2(cosval, -sinval, sinval, cosval);//旋转dir = mul(dir, rotmatrix);//再平移回原位置dir += _DistortCenter.xy;//采样noise图fixed4 noise = tex2D(_NoiseTex, i.uv);//noise的权重 = 参数 * 距离,越靠近外边的部分,扰动越严重float2 noiseOffset = noise.xy * _DistortStrength * dir;//用偏移过的uv+扰动采样MainTexreturn tex2D(_MainTex, dir + noiseOffset);}ENDCGSubShader {Pass{ZTest AlwaysCull Off ZWrite OffFog { Mode off }//调用CG函数    CGPROGRAM//使效率更高的编译宏#pragma fragmentoption ARB_precision_hint_fastest //vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img#pragma vertex vert_img#pragma fragment frag ENDCG}}
}

C#脚本部分,仍然使用了两条曲线进行控制,一条控制旋转值,一条控制扰动值:

/********************************************************************FileName: PassthoughEffect.csDescription: 漩涡扭曲效果Created: 2017/05/10by :puppet_master
*********************************************************************/
using UnityEngine;
using System.Collections;public class RotationDistortEffect : PostEffectBase
{//收缩强度[Range(0, 20.0f)]public float distortFactor = 1.0f;//扭曲中心(0-1)屏幕空间,默认为中心点public Vector2 distortCenter = new Vector2(0.5f, 0.5f);//噪声图public Texture NoiseTexture = null;//屏幕扰动强度[Range(0, 2.0f)]public float distortStrength = 1.0f;//屏幕扭曲时间public float passThoughTime = 3.0f;//当前时间private float currentTime = 0.0f;//曲线控制权重public float rotationCurveFactor = 10.0f;//屏幕全传效果曲线控制public AnimationCurve rotationCurve;//扰动曲线系数public float distortCurveFactor = 0.1f;//屏幕扰动效果曲线控制public AnimationCurve distortCurve;void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortFactor", distortFactor);_Material.SetVector("_DistortCenter", distortCenter);_Material.SetFloat("_DistortStrength", distortStrength);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}//ContexMenu,可以直接在Component上右键调用该函数,比较好用的小技巧哈[ContextMenu("Play")]public void StartPassThoughEffect(){currentTime = 0.0f;StartCoroutine(UpdatePassthoughEffect());}private IEnumerator UpdatePassthoughEffect(){while (currentTime < passThoughTime){currentTime += Time.deltaTime;float t = currentTime / passThoughTime;//根据时间占比在曲线(0,1)区间采样,再乘以权重作为收缩系数distortFactor = rotationCurve.Evaluate(t) * rotationCurveFactor;distortStrength = distortCurve.Evaluate(t) * distortCurveFactor;yield return null;//结束时强行设置为0distortFactor = 0.0f;distortStrength = 0.0f;}}
}

配置两条曲线以及参数:


漩涡扭曲效果动态图如下:

Unity Shader-后处理:时空扭曲效果相关推荐

  1. Unity Shader 窗前雨滴效果衍生(表面水滴附着)

    Unity Shader 窗前雨滴效果衍生(表面水滴附着) 霓虹中国视频截图 现实中的水珠附着效果 实现思路 1.首先创建一个Cube来作为实现效果的物体 2.创建一个Shader开始着色器的编写 实 ...

  2. Unity Shader·屏幕破碎效果

    Unity Shader·屏幕破碎效果 前言 最近在做一个新的MMD(用Unity来实现),其中用到了一些好看的渲染技术在这里分享一下. 视频链接 https://www.bilibili.com/v ...

  3. Unity Shader 之 透明效果

    本文引用 Unity Shader入门精要 开启透明混合后,一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值外,还有--透明度.透明度为1,则完全不透明,透明度为0,则完全不会显示. 在Unity ...

  4. Unity Shader - 翻书效果

    今天实现一个简单的翻书的效果,话不多说,先上一张效果图: 这里就随便用的一张纹理了,我们还是称为"翻木板"吧,哈哈. 实现过程: 其实这个效果实现起来还是挺简单的,大概思路其实就是 ...

  5. unity shader 抖音效果

    最近开始学习了unity shader,所以想要做一些简单的效果,来巩固一下知识.我第一个想做的就是做一些类似于抖音的效果.(PS:最近学习了markdown,所以就用markdown开始写博客了 ) ...

  6. Unity Shader 实现鬼魂效果

    Shader 实现鬼魂效果 前言 前言 我们在游戏中经常会角色碰到角色的情况,大多数游戏中角色和角色重叠的时候会显示一个虚幻的鬼影而不是完全遮挡,那么这个鬼影效果怎么实现呢?接下来我们就实现这样的一个 ...

  7. Unity Shader - 后处理:油画效果

    效果图:                                                                                     效果对比图(一)

  8. Unity Shader 屏幕后效果——高斯模糊

    高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础. 实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客: https://www.cnblogs.c ...

  9. Unity Shader 屏幕后效果——Bloom外发光

    Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...

  10. Unity Shader 实现磨皮效果

    最近在做一些UI使用的shader,大部分是对UV进行一些操作,今天看需求文档时发现美术同学的要求里有一项是类似磨皮的效果,本来我也比较好奇这些美颜效果都是怎么做的,所以就趁此机会实验一下.查了一大堆 ...

最新文章

  1. python 数据增强
  2. Python PIL反色混合
  3. Tengine ngx_http_sysguard_module 过载保护模块使用
  4. 目标驱动的软件度量(选译)
  5. 模板方法模式(Template Method Pattern)学习笔记
  6. 前端学习(592):使用snippets辅助debugging
  7. 浅尝JQ AJAX
  8. [转]关闭不必要端口 让电脑固若金汤
  9. 像素生存者2为什么显示服务器不可用,像素生存者2为什么更新了玩不了 | 手游网游页游攻略大全...
  10. 第九期 HG255d硬件分析 《路由器就是开发板》
  11. BiLSTM-CRF模型理解
  12. R语言保存EXCEL小技巧
  13. 梯度消失和爆炸原因以及解决方法
  14. 发一个自己常用的通信词汇缩写表(实时更新)
  15. Ubuntu_18.04安装网易云音乐
  16. 建筑行业现行相关税收政策及优惠措施汇编
  17. 高难度c语言编程题,高难度脑筋急转弯题目合集带答案
  18. 云的新出路迷你云?轻松搭建私有云平台 转载7
  19. 7、统计字母、空格、数字 与 其它字符的个数
  20. 常用颜色代码表以及中国传统颜色名录

热门文章

  1. unity愤怒的小鸟学习制作(一)
  2. Qt6-Qt5代码移植到Qt6
  3. 名画93 马远《水图卷》
  4. Android listview和adapter
  5. 南京工业大学浦江学院计算机学院,计算机与通信工程学院
  6. mediaPlayer的seekto方法
  7. 逻辑思维训练题(共75道)
  8. dataFEED OPC Suite V5.20轻松应对Windows DCOM安全更新
  9. 手机cpu厂商和手机cpu架构
  10. javaSE:基础知识【1】