当前位置: 首页 > article >正文

unity3d————Mathf.Lerp() 函数详解

Mathf.Lerp()是Unity中的一个非常有用的数学函数。它的名字来自于“Linear Interpolation”的缩写,意思是“线性插值”。

想象一下,你有两个点,一个点叫A,另一个点叫B。现在,你想在A和B之间找到一个新的点,这个点不是随便找的,而是根据一定的比例来确定的。这个比例我们称之为t,t的范围是从0到1。

  • 当t=0时,新点就是A点。
  • 当t=1时,新点就是B点。
  • 当t在0和1之间时,新点就会在A和B之间,离A和B的距离取决于t的值。

Mathf.Lerp()函数就是帮你找到这个新点的位置的。

为什么要用Mathf.Lerp()?

  1. 平滑过渡:在游戏开发中,经常需要让物体平滑地从一个位置移动到另一个位置。使用Mathf.Lerp()可以实现这种平滑过渡的效果,让物体看起来移动得更加自然。

  2. 动画效果:在制作动画时,Mathf.Lerp()可以帮助你创建两个状态之间的平滑变化,比如颜色的渐变、物体大小的缩放等。

  3. 性能优化:在某些情况下,直接计算物体的新位置可能比较复杂或者耗时。使用Mathf.Lerp()可以简化计算,提高游戏的性能。

  4. 灵活性Mathf.Lerp()不仅可以用于位置的插值,还可以用于其他任何可以用数字表示的属性的插值,比如颜色、旋转角度、缩放比例等。

计算公式:

result = start + (end - start) * t    

下面来看这俩个例子实例代码:

public class CudeFollow : MonoBehaviour
{
    // B位置信息
    public Transform B;

    //跟随速度
    public float speed = 10;
    private Vector3 pos;

    private Vector3 startPos;
    private Vector3 bNowPos;
    float time;
    // Update is called once per frame
    void Update()
    {
        //插值运算用法一
        //每帧改变start的值——变化速度先快后慢,位置无限接近,但是不会得到end位置
        //start = Mathf.Lerp(start, 10, Time.deltaTime);
        //result = start + (end - start)*t
        //pos = this.transform.position;
        //pos.x = Mathf.Lerp(pos.x, B.position.x, Time.deltaTime);
        //pos.y = Mathf.Lerp(pos.y, B.position.y, Time.deltaTime);
        //pos.z = Mathf.Lerp(pos.z, B.position.z, Time.deltaTime);


        //第二种 就是 匀速运动
        if (bNowPos != B.position)
        {
            time = 0;
            bNowPos = B.position;
            startPos = this.transform.position;
        }

        time += Time.deltaTime;

        pos.x = Mathf.Lerp(startPos.x, bNowPos.x, time);
        pos.y = Mathf.Lerp(startPos.y, bNowPos.y, time);
        pos.z = Mathf.Lerp(startPos.z, bNowPos.z, time);
        this.transform.position = pos;
    }
}

第一种是先快后慢(物体A靠近物体B的速度是先快后慢),那这是为什么呢? 

首先,让我们澄清一下 Mathf.Lerp() 函数的行为。Mathf.Lerp(a, b, t) 会根据 t(一个通常在 0 到 1 之间的浮点数)返回 a 和 b 之间的一个插值。当 t 接近 0 时,返回值更接近 a;当 t 接近 1 时,返回值更接近 b。如果 t 是 Time.deltaTime(即上一帧到当前帧的时间间隔),那么插值的速度将取决于这个时间间隔的大小以及 a 和 b 之间的距离。

  1. 插值参数:您使用 Time.deltaTime 作为插值参数 tTime.deltaTime 是一个很小的数,表示上一帧到当前帧的时间间隔(通常以秒为单位)。因此,每次插值时,物体 A 的位置只会向物体 B 的位置移动一小步。

  2. 逐帧插值:在 Update() 方法中,您每帧都对物体 A 的位置进行插值运算。由于 Time.deltaTime 很小,每帧的移动量也很小,导致物体 A 逐渐靠近物体 B,但速度越来越慢。这是因为随着 A 越来越接近 B,每帧需要移动的距离变得越来越小。

  3. 插值的目标:在您的代码中,插值的目标是物体 B 的当前位置。如果物体 B 是静止的,那么物体 A 最终会停在物体 B 的位置(但由于 Time.deltaTime 的使用,它可能永远不会完全到达,只是无限接近)。如果物体 B 在移动,那么物体 A 会尝试跟随物体 B 的移动。

  4. 速度感知:由于插值是基于时间的,所以物体 A 移动的速度会感觉上是逐渐减慢的。这是因为随着 A 接近 B,每帧移动的绝对距离在减小,尽管相对移动的比例可能保持不变。

或者我在分析分析按我自己理解,其实也是看公式,t 不变  然后start 跟 end 距离不断减小 意味着 每一帧移动的距离都是不断减小的,时间一样 ,每一帧的速度就不断减小,看起来就是不断变慢过程,

第二种是匀速,为什么呢?

  1. 初始化条件
    • 当 bNowPos(上一次记录的B的位置)不等于 B.position(B当前的位置)时,说明B已经移动了。
    • 此时,您重置 time 为0,并更新 bNowPos 和 startPos 为当前的位置。这相当于在每次B移动时重新开始一个新的插值过程。
  2. 插值过程
    • 在每一帧中,您使用 Mathf.Lerp(startPos, bNowPos, time) 来计算A的新位置。
    • 这里的 time 是从B开始移动(或者从A开始跟随B的新的位置)时累积的时间。
    • Mathf.Lerp 函数会根据 time 在 startPos 和 bNowPos 之间进行线性插值。因为 time 是均匀增加的(每帧加上 Time.deltaTime),所以插值的结果也是均匀变化的,即A会以恒定的速度向B的当前位置移动。
  3. 匀速的原因
    • 在这种方法中,A的移动速度是由 time 的增加速率决定的,而 time 是每帧均匀增加的(通过 Time.deltaTime)。
    • 不像第一种方法中使用 Time.deltaTime 作为插值参数(这会导致速度逐渐减慢),在这里 Time.deltaTime 只是用来更新 time 变量,而 time 变量本身则用于控制插值的进度。
    • 因此,无论A和B之间的距离如何,A都会以相同的速度(在插值空间内)向B移动,直到到达B的位置。这个速度是由插值函数的线性性质和 time 的均匀增加共同决定的。
  4. 到达目标
    • 在这种方法中,当 time 增加到足够大时(具体取决于 startPos 和 bNowPos 之间的距离以及插值的速度),A最终会到达B的位置。
    • 与第一种方法不同,这里没有使用 Time.deltaTime 来直接控制每帧的移动量,而是用它来累积时间,从而通过插值函数间接控制移动量。这导致了匀速运动的效果。

总之,第二种方法实现了匀速运动,因为它通过累积时间来控制插值的进度,而不是直接使用每帧的时间间隔来控制移动量。这种方法更加直观和可控,特别是当您想要实现恒定的跟随速度时。

实际上,这两种方法在理论上都不会使物体A完全到达物体B的位置,而是会无限接近。但在实际的游戏或模拟环境中,这种差异通常是可以忽略的。

第一种方法(使用Time.deltaTime作为插值参数)

在这种方法中,Mathf.Lerp()函数的t参数是Time.deltaTime。由于Time.deltaTime代表上一帧到当前帧的时间间隔,它总是一个非零的浮点数(除非游戏暂停或帧率极高,但在实际情况下这不会发生)。因此,每帧的插值都会使物体A向物体B移动一个非常小的距离。即使物体B是静止的,物体A也可能永远不会完全到达B的位置,因为它总是在接近但永远不会完全等于B的位置。

第二种方法(累积时间作为插值参数)

在第二种方法中,您使用了一个累积的时间变量time来控制插值的进度。这个变量是通过每帧加上Time.deltaTime来累积的。虽然这种方法看起来更像是一个匀速运动的过程,但同样由于浮点数的精度限制和Time.deltaTime的非零性,物体A也可能永远不会完全到达物体B的位置。

然而,在实际应用中,当物体A足够接近物体B时,由于视觉上的限制和浮点数的精度问题,玩家或观察者通常无法区分物体A是否已经完全到达了物体B的位置。因此,在大多数情况下,可以认为物体A已经“到达”了物体B的位置,即使从数学的角度来看它们之间可能仍然存在一个极小的差距。

 


http://www.kler.cn/a/373662.html

相关文章:

  • uniapp实现【时间戳转换为日期格式(年-月-日 时-分-秒)】
  • Go使用SIMD指令——以string转为整数为例
  • 10.30学习
  • vscode的一些使用心得
  • mac ssh 连接 linux 服务器
  • asp.net webapi实现FileStreamResult
  • 从0开始深度学习(21)——读写数据和GPU
  • 【Nas】X-DOC:Mac mini 安装 ZeroTier 并替换 planet 实现内网穿透
  • 人工智能中的机器学习和模型评价
  • RNN在训练中存在的问题
  • 常见的机器学习模型汇总
  • C++ 复习记录(个人记录)
  • 基于Multisim的四位抢答器设计与仿真
  • 数据结构,问题 A: 翻转字符串
  • 野火鲁班猫4 (RK3588)系统配置
  • Mybatis 统计sql运行时间
  • 嵌入式linux跨平台基于mongoose的TCP C++类的源码
  • 如何在macOS开发中给 PKG 签名和公证(productsign+notarytool)
  • Vue中path和component属性
  • JAVA基础练习题
  • 攻防世界 MISC miao~详解
  • 无人机测绘遥感技术算法概述!
  • Q-learning原理及代码实现
  • 初识 BPF:从 Hello World 开始的内核编程之旅
  • SpringBoot技术:闲一品交易的未来
  • 标准数字隔离器主要特性和应用---腾恩科技