前言
这次来实作上章提到的屏幕扭曲效果,需要用到这张图(文章最后提供链接)
5.1位移图
先稍微花点时间思考一下这张图怎么用。
5.2像素采样偏移方法
纹理中红色的部分代表uv在x轴上的位移,而绿色则表示uv在y轴上的位移。
正文
为此我们的shader需要一个额外的二维纹理属性用以存储位移图,以及一个magnitude属性,用来调整我们的扭曲效果的强度。以上一章写好的shader为基础,加入以下代码:
- Properties{
- _MainTex("Main Text", 2D) = "white" {}
- _DisplacementTex("Displacement Texture", 2D) = "white" {}
- _Magnitude("Magnitude", Range(0, 1)) = 0
- }
复制代码
新增一个二维的位移纹理,接着加上一个magnitude拖动条。记得在使用之前要先在CGPROGRAM里面定义这些属性:
sampler2D _MainTex;
sampler2D _DisplacementTex;
float _Magnitude;
接下来在frag函数里面的运算可能有些复杂,看不懂记得来回看多几遍:
- float4 frag(v2f i) : SV_Target
- {
- float2 disp = tex2D(_DisplacementTex, i.uv).xy;
- disp = ((disp * 2) - 1) * _Magnitude;
- float4 color = tex2D(_MainTex, i.uv + disp);
- return color;
- }
复制代码
首先第一步是定义了一个float2的disp来对位移图进行采样,下面一行做了一些数学上的转换。因为从uv中获取的值是介于0到1之间的,这样的数值算出来的扭曲效果会不明显,所以要让值定位到-1到1之间,让界面有飘来飘去的感觉,并乘上magnitude让我们可以控制强度。最后,将我们的主纹理采样为法向量,但这次,我们将uv加上位移的量
然后回到材质的面板,位移图拖到displacement texture的位置,然后拖动magnitude的拖动条,得到下面的效果
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值就已经改变过了。到此为止,思路上的提示我已经给得差不多,现在到你思考了。
动态扭曲的代码:
- float4 frag (v2f i) : SV_Target
- {
- float2 distuv = float2(i.uv.x + _Time.x * 2, i.uv.y + _Time.x * 2);
- float2 disp = tex2D(_DisplacementTex, distuv).xy;
- disp = ((disp * 2) - 1) * _Magnitude;
- float4 col = tex2D(_MainTex, i.uv + disp);
- return col;
- }
复制代码
随便给magnitude设一个值就可以看到这样的动态扭曲效果:
5.4美丽的香菜
位移图链接:
https://pan.baidu.com/share/init?surl=dtMOiK5WstENYspRUyv0JQ
提取码:ewjq
相关阅读:
Shader从入门到跑路:朴实无华的图形学基础
Shader从入门到跑路:自定义纹理输入
Shader从入门到跑路:屏幕后处理效果
作者:俊铭
https://zhuanlan.zhihu.com/p/86237202