Unity3D MoveTowards、Lerp、Slerp

Reading time ~1 minute

MoveTowards、Lerp、Slerp这三个函数相信大家经常遇到,这些都是在做一些过渡操作时需要用到的,那么它们间的具体差别是什么呢?其实要搞清楚它们的区别,只要仔细看官方说明,明白它们的具体用途是什么。

MoveTowards

Mathf、Vector2、Vector3等许多类都有这个方法,意思都差不多。以Vector3为例,函数原型为:

1
public static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);

作用是将当前值current移向目标target。(对Vector3是沿两点间直线) maxDistanceDelta就是每次移动的最大长度。 返回值是当current值加上maxDistanceDelta的值,如果这个值超过了target,返回的就是target的值。

例子:

1
2
3
4
5
//表示以每秒moveMax的速度从Current移动到Target。
//因为Current和Target距离是4,所以当moveMax 等于0.5f,用时8秒,moveMax等于2时,用时2秒。
Vector3 Current  = new Vector3(0, 0, 0);
Vector3 Target = new Vector3(0, 0, 4);
Current = Vector3.MoveTowards(Current, Target, moveMax * Time.deltaTime);

Lerp

Lerp表示线性插值,很多地方都用到了它。这里仍以Vector3为例,函数原型是:

1
public static Vector3 Lerp(Vector3 a, Vector3 b, float t);

它的作用就是按照t计算a和b之间的插值。t的取值范围是[0, 1]。 简单理解就是当t=0, 返回值是a,当t=1,返回值是b。同理,t=0.1时是a到b的10%。t就代表了a到b的百分比。

线性插值图示

例1:

1
2
3
4
5
6
7
8
9
10
11
//在time时间内移动物体
private IEnumerator MoveObject(Vector3 startPos, Vector3 endPos, float time)
{        
        var dur = 0.0f;
        while (dur <= time)
        {
            dur += Time.deltaTime;
            transform.position = Vector3.Lerp(startPos, endPos, dur / time);
            yield return null;
        }
}

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//以指定速度speed移动物体
private IEnumerator MoveObject_Speed(Vector3 startPos, Vector3 endPos, float speed)
{
        float startTime = Time.time;
        float length = Vector3.Distance(startPos, endPos);
        float frac = 0;

        while (frac < 1.0f)
        {
            float dist = (Time.time - startTime) * speed;
            frac = dist / length;
            transform.position = Vector3.Lerp(startPos, endPos, frac);
            yield return null;
        }
}

Slerp

球形插值在Vector3、Quaternion等类都有使用,一般多在Quaternion的旋转操作时使用。

对于Vector3:

1
public static Vector3 Slerp(Vector3 a, Vector3 b, float t);

这里球形插值与线性插值不同的地方在于,它将Vectors视为方向而不再是点。返回的向量方向,它的角度是根据a和b的角度插值,而它的长度是根据a和b的长度插值。 可以用其模拟太阳的升降变化等操作。

对于Quaternion:

1
public static Quaternion Slerp(Quaternion a, Quaternion b, float t);

计算a与b的球形插值。 Quaternion的Lerp与Slerp结果都是一样的,Lerp的效率会比Slerp高些,但是当旋转值a和b离得比较远时,Lerp的效果会非常差。 这是一段Lerp和Slerp的视频演示:https://www.youtube.com/watch?v=uNHIPVOnt-Y

或者看下图:

Lerp与Slerp

红点是起点,绿点是终点。蓝色线是Lerp的轨迹,白线是Slerp的轨迹。

注意:

对于插值(Slerp和Lerp)运算中的t,要明白它代表的是百分比,直接对齐赋值时间如Time.deltaTime是没意义的,因为如果t为1的话,永远都不会到达目标值。

Scriptable Objects 及 游戏架构

Scriptable Objects 相关介绍,及基于其的游戏架构技术 Continue reading

AssetBundle 最佳实践

Published on January 29, 2019

AssetBundle 基础总结

Published on January 27, 2019