slideshow Effect 2d更新了新版本,之前讲到的没有收录的效果已经都收录进去了。
老用户可以更新,新用户有兴趣可以支持一下。临近放假,犯懒不想写太长的文,毕竟画图也比较费劲,所以今天讲一下比较简单的内容。
制作无限循环背景的方法已经基本可以说是众所周知,就是在移动一张图片的时候,在边缘使用同样的图片来补充。在unity中,可以用非常直观的方法来实现。
首先准备一张四方连续的图片,如果只需要在一个方向滚动,那么而方连续也没问题。设置图片的import setting,将wrap mode设为repeat,之后将其作为标准材质的贴图,添加一个animation,让Offset的值从0到1变化就完成了。
然而这样做毕竟显得不那么高级,用来单独写一篇文章总归是不行的。于是我们照例先声明几个property,来设定图片滚动方向以及处于循环中的位置。
Properties {
_MainTex ("Main Texture", 2D) = "black" {}
_Rotation("Rotation", Range(0,360)) = 0.0
[Space(10)]
_Progress("Progress", Range(0,1))=0
}
为了方便直观,角度的值使用了0~360范围。
接下来在vert函数中根据角度和progress,计算当前帧里uv偏移的量。
由于对于整个图片来说,同一帧里所有位置的uv偏移量是一样的,所以这一计算可以在vert函数里进行。
v2f vert(appdata_img v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float Rot = _Rotation * (3.1415926f/180.0f);
float s = sin(Rot);
float c = cos(Rot);
o.uvTA=v.texcoord +fixed2(s,c)*_Progress ;
return o;
}
由于vert函数中只对uv进行了操作,在frag函数中只需要根据偏移后的uv绘制贴图即可。
return tex2D(_MainTex, i.uvTA).rgba ;
看一下效果~:
水平和竖直方向都很好的达到了我们想要的效果,但是当给rotation一个自由的角度时,问题出现了
看来这是由角度和偏移的计算方法导致的。在旋转一个角度后,x或y的方向的偏移量可能并不是一个整数,或者是贴图最小重复单元的整数倍数。
如果希望让progress为0和1时计算出的偏移量相同,可以分别定义x和y两个方向的速度。此速度是以偏移的倍数为单位的。
_SpeedX("speedX", Range(0,5)) = 1.0
_SpeedY("speedY", Range(0,5)) = 1.0
在计算uv时,也将x和y两个方向分别计算。
o.uvTA=(v.texcoord) +fixed2(_SpeedX,_SpeedY)*_Progress ;
这回再看一下效果,问题解决了!
在贴图取色走马灯这一章中,我们有讲到系统时间 _Time的使用。
saku一只松鼠:[Unity+shader]从贴图中采样取色的走马灯zhuanlan.zhihu.com在制作贴图循环滚动效果的时候,同样可以使用这个东西。
首先声明几个property,来设定图片滚动的速度和方向。
Properties {
_MainTex ("Main Texture", 2D) = "black" {}
_Speed("speed", Range(0,3)) = 1.0
_Rotation("Rotation", Range(0,360)) = 0.0 //为了方便直观,角度的值使用了0~360范围
}
接下来我们要做的,就是根据角度和速度,计算当前帧里uv偏移的量。
关于unity内置的一些时间函数,可以阅读: https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
v2f vert(appdata_img v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float Rot = _Rotation * (3.1415926f/180.0f);
float s = sin(Rot);
float c = cos(Rot);
o.uvTA=(v.texcoord)*_MainTex_ST.xy+fixed2(s,c)*(_Time.y * _Speed) -_MainTex_ST.zw;
return o;
}
与在 贴图中采样取色的走马灯这一章中略有不同,如果使用_SinTime的话,会得出不太一样的效果。
这里有个小小的缺陷:由于_Time给出的是从运行开始到现在所经过的时间,所以计算出的是从运行到当前时间的总的偏移量。也就是说,如果在运行途中更改了rotation的话,是下一帧的偏移量会直接跳到新计算出的值,而不会有平滑过渡的效果。
要解决这一缺陷,可以使用增加一个脚本的方法,将从运行开始累积的偏移量保存在脚本中,然后在每一帧都将新的偏移量传递到材质里。
在shader中增加两个变量,分别代表x和y方向的偏移。由于这两个值在使用的时候不需要被看到或手动修改,不必把它加入到properties里。
float _uvx,_uvy;
在物体上新建一个脚本,由于每一帧的偏移量变化在脚本中实现,所以需要添加rotation和speed两个变量到脚本中,同时,shader里的rotation和speed就可以去掉了。
using UnityEngine;
public class tutLoopBG : MonoBehaviour {
Material material;
Vector2 offsetuv;
[SerializeField,Range(0,360)]
float rotation;
[SerializeField]
float speed;
void Start () {
if (gameObject.GetComponent<Renderer> () && material==null) {
material = gameObject.GetComponent<Renderer> ().sharedMaterial;
offsetuv=new Vector2(0,0);
}
}
void Update () {
float s = Time.deltaTime* speed*Mathf.Sin (rotation * Mathf.Deg2Rad);
float c = Time.deltaTime* speed*Mathf.Cos (rotation * Mathf.Deg2Rad);
offsetuv.x += s;
offsetuv.y += c;
material.SetFloat ("_uvx", offsetuv.x);
material.SetFloat ("_uvy", offsetuv.y);
}
}
这里,首先在start函数中获取到当前物体上的材质,以备后用。在每次update时,使用deltatime计算偏移量与上一帧之间的变化,累加在offsetuv中。之后将累计过的偏移量传递给材质。
在shader的vert函数中,只需要加上最终的偏移量即可。
o.uvTA=(v.texcoord*_MainTex_ST.xy-_MainTex_ST.zw)+fixed2( _uvx,_uvy);
当然还有另一种方法:
material.SetVector ("_MainTex_ST",new Vector4(1,1,offsetuv.x,offsetuv.y));
这里Vector4(1,1,offsetuv.x,offsetuv.y)的四个数值即xy方向的tilling与xy方向的offset。直接对贴图的tilling and offset进行赋值,这样就可以将_uvx,_uvy省略掉了。
这章所用到的资源在这里获取:
sakuraplus/make-terrain-with-google-elevationgithub.com获取更多特效,Buy me a coffee:
Asset Storeu3d.as前几章讲到的内容已经在版本1.2中得到了更新。