animation 循环_[Unity+shader]无限循环背景的制作

9d80a39ed7f14ae83d635349dad09534.png

slideshow Effect 2d更新了新版本,之前讲到的没有收录的效果已经都收录进去了。

老用户可以更新,新用户有兴趣可以支持一下。临近放假,犯懒不想写太长的文,毕竟画图也比较费劲,所以今天讲一下比较简单的内容。


制作无限循环背景的方法已经基本可以说是众所周知,就是在移动一张图片的时候,在边缘使用同样的图片来补充。在unity中,可以用非常直观的方法来实现。

首先准备一张四方连续的图片,如果只需要在一个方向滚动,那么而方连续也没问题。设置图片的import setting,将wrap mode设为repeat,之后将其作为标准材质的贴图,添加一个animation,让Offset的值从0到1变化就完成了。

7f9d40ef5a3e7704cf3a14dce7087ecb.png

bb2cc22c22513c63e3c8fb8c77e23633.png

f75bbae642a092e2d2b8c33afe3e4417.gif
一个最基础的循环滚动背景,如果让offset的x和y都从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;
		}

a9376e06e691f69d7b20045d208d2b6d.png
rotation是0的时候,原本uv.y是0的位置的逐渐向1靠近,结果就是,图片看起来逐渐向下滚动了。

由于vert函数中只对uv进行了操作,在frag函数中只需要根据偏移后的uv绘制贴图即可。

			return  tex2D(_MainTex, i.uvTA).rgba ;

看一下效果~:

898bca0a36b82ccdbaabf9078519c84d.gif

276e88fe2a1f03d47f8be251ebcea7a4.gif

水平和竖直方向都很好的达到了我们想要的效果,但是当给rotation一个自由的角度时,问题出现了

f786a42f8d03a9f5094394aa341dc6ff.gif
当角度是30°时,progress的值是0和1时并不能呈现出同样的偏移效果

看来这是由角度和偏移的计算方法导致的。在旋转一个角度后,x或y的方向的偏移量可能并不是一个整数,或者是贴图最小重复单元的整数倍数。

38213941346663b644219fc5f2f5b535.png
在rotation是0或90的倍数时,由于fixed2(s,c) 是整数而不会显现出问题

如果希望让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 ;

1df217879d6e2c2885caf2347536014d.png
当speedx=2,speedy=1的时候,progress从0到1的过程跨越的是横向两倍纵向一倍的贴图大小

这回再看一下效果,问题解决了!

90a885cb7ebd906ef9e1de0d9b993713.gif
加上了一个cell变量,来表示最小的循环单元的大小,在贴图上包含重复元素的时候比较方便使用

在贴图取色走马灯这一章中,我们有讲到系统时间 _Time的使用。

saku一只松鼠:[Unity+shader]从贴图中采样取色的走马灯​zhuanlan.zhihu.com
340169ce02ac835911619addf4079ea4.png

在制作贴图循环滚动效果的时候,同样可以使用这个东西。

首先声明几个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的话,会得出不太一样的效果。

0d065606438a4cc20c02b3542a84cbfe.gif
单纯将time替换成sintime,就会成这个摇摇摆摆的样子

这里有个小小的缺陷:由于_Time给出的是从运行开始到现在所经过的时间,所以计算出的是从运行到当前时间的总的偏移量。也就是说,如果在运行途中更改了rotation的话,是下一帧的偏移量会直接跳到新计算出的值,而不会有平滑过渡的效果。

ec3a2a67c58f044cdb892faeac4441cd.gif
转了角度之后一跳一跳的,虽然可能在实际应用中没多大影响

要解决这一缺陷,可以使用增加一个脚本的方法,将从运行开始累积的偏移量保存在脚本中,然后在每一帧都将新的偏移量传递到材质里。

在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);

2bb97dbc8da786d03ef441f31f8fda36.gif
这下好了!

当然还有另一种方法:

		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-elevation​github.com

获取更多特效,Buy me a coffee:

Asset Store​u3d.as

前几章讲到的内容已经在版本1.2中得到了更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值