游戏开发技术论坛

 找回密码
 立即注册
搜索
查看: 1681|回复: 0

Shader从入门到跑路:实作屏幕扭曲效果

[复制链接]

1万

主题

1万

帖子

3万

积分

版主

Rank: 7Rank: 7Rank: 7

积分
36572
发表于 2020-3-20 13:24:32 | 显示全部楼层 |阅读模式
v2-0802c4f31a3f6733eae6ea71e252a609_1200x500.jpg


前言

这次来实作上章提到的屏幕扭曲效果,需要用到这张图(文章最后提供链接)

1.jpg
5.1位移图

先稍微花点时间思考一下这张图怎么用。

2.jpg
5.2像素采样偏移方法

纹理中红色的部分代表uv在x轴上的位移,而绿色则表示uv在y轴上的位移。


正文

为此我们的shader需要一个额外的二维纹理属性用以存储位移图,以及一个magnitude属性,用来调整我们的扭曲效果的强度。以上一章写好的shader为基础,加入以下代码:

  1. Properties{
  2.         _MainTex("Main Text", 2D) = "white" {}
  3.         _DisplacementTex("Displacement Texture", 2D) = "white" {}
  4.         _Magnitude("Magnitude", Range(0, 1)) = 0
  5. }
复制代码

新增一个二维的位移纹理,接着加上一个magnitude拖动条。记得在使用之前要先在CGPROGRAM里面定义这些属性:

sampler2D _MainTex;

sampler2D _DisplacementTex;

float _Magnitude;

接下来在frag函数里面的运算可能有些复杂,看不懂记得来回看多几遍:

  1. float4 frag(v2f i) : SV_Target
  2. {
  3.         float2 disp = tex2D(_DisplacementTex, i.uv).xy;
  4.         disp = ((disp * 2) - 1) * _Magnitude;
  5.         float4 color = tex2D(_MainTex, i.uv + disp);
  6.         return color;
  7. }
复制代码

首先第一步是定义了一个float2的disp来对位移图进行采样,下面一行做了一些数学上的转换。因为从uv中获取的值是介于0到1之间的,这样的数值算出来的扭曲效果会不明显,所以要让值定位到-1到1之间,让界面有飘来飘去的感觉,并乘上magnitude让我们可以控制强度。最后,将我们的主纹理采样为法向量,但这次,我们将uv加上位移的量

然后回到材质的面板,位移图拖到displacement texture的位置,然后拖动magnitude的拖动条,得到下面的效果


3 (1).gif
5.3热起来香菜都扭曲

其实如果你直接把这个效果放到游戏里面,也可以制造一些火焰山的感觉,热到扭曲就是说的这个,连周边的空气都要与图像混合在一齐。

但是要手动拖动magnitude毕竟还是太逊了,我们不能给程序猿丢脸,得用代码从外部改变内部状态。

我们可以用unity提供的一个叫_Time的参数,这个参数是写在了UnityCG.cginc文件里的。_它有很多用法,比如_Time.x返回的是当前的时间的20分之一,_Time.y则是当前时间等等。

https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

在告诉你解法之前,我强烈建议你先遮住这一段下面的代码部分(伸手党的同学可以跳过这一部分),自己好好想一想用_Time参数怎么实现动态扭曲。首先思考一下刚才我们是怎么实现扭曲的。我们将位移图的采样结果添加到uv上,在对主纹理(在这里就是屏幕)采样时使用偏移过的uv来进行采样,便会得到渲染效果。(没懂?划上去看代码,依然没懂翻前一章看OnRenderImage的代码)那么,如果扭曲是动态的,就是说,一开始,uv值就随着时间的推移而改变,我们在对位移图进行采样的时候,uv值就已经改变过了。到此为止,思路上的提示我已经给得差不多,现在到你思考了。

动态扭曲的代码:

  1. float4 frag (v2f i) : SV_Target
  2. {
  3.         float2 distuv = float2(i.uv.x + _Time.x * 2, i.uv.y + _Time.x * 2);

  4.         float2 disp = tex2D(_DisplacementTex, distuv).xy;
  5.         disp = ((disp * 2) - 1) * _Magnitude;

  6.         float4 col = tex2D(_MainTex, i.uv + disp);
  7.         return col;
  8. }
复制代码

随便给magnitude设一个值就可以看到这样的动态扭曲效果:

4 (1).gif
5.4美丽的香菜


5.jpg

位移图链接:

https://pan.baidu.com/share/init?surl=dtMOiK5WstENYspRUyv0JQ

提取码:ewjq

相关阅读:
Shader从入门到跑路:朴实无华的图形学基础
Shader从入门到跑路:自定义纹理输入
Shader从入门到跑路:屏幕后处理效果

作者:俊铭
https://zhuanlan.zhihu.com/p/86237202

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2023-2-6 14:10

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表