Unity插值函数Lerp()与增量时间Time.deltatime
一、Unity插值函数Lerp()
通过官方文档简单了解插值函数(https://docs.unity3d.com/ScriptReference/index.html),可以看到插值函数有很多

Mathf.Lerp()

从最简单的数学插值来看,插值函数接收三个参数a,b,t,在ab之间,以t作为比例来插值。
例如,Lerp(0, 10, 0.4f),此时返回4,即 a + (b - a) * t
注意,第三个参数要小于1,如果大于1,则还是返回b。
其他的插值也类似于此,只不过插值的对象变为向量,颜色等等。
二、增量时间Time.deltatime
游戏都是一帧一帧显示的,平时说的60FPS就是1秒60帧;帧率越高,游戏运行就越流畅。
增量时间deltatime,就是从上一帧到现在所经过的时间。如果游戏稳定在60FPS,那么增量时间就是1/60s,当然实际游戏运行帧数肯定在不断变化,所以Time.delta的值也在不断地变化。简单来说,Time.deltatime就是运行每一帧所花的时间。

三、插值函数的作用
在看官方文档以及其他的代码时,经常发现插值函数的第三个参数往往和增量时间有关,如:
using UnityEngine; public class Example : MonoBehaviour
{
Transform target;
float speed = 0.1f;
void Update()
{
transform.position = Vector3.Lerp(transform.positon, target.position, Time.deltatime * speed);
}
}
那么为什么线性插值的第三个参数要用到增量时间呢?
首先,需要理解为什么要利用插值函数。
不妨想象以下游戏场景,在主人身后有一只宠物,它会时刻跟在主人身后,如果主人走远了,它也会快速跟上。

可以发现两点,第一,宠物不是瞬间移动到主人身后的,而是一点一点走过来的,第二,宠物和主人离得越远,宠物跟随的速度就越快,离主人越近,宠物的速度就越慢,而Lerp()函数就可以实现弹性跟随的效果。
transform.position = Vector3.Lerp(transform.positon, target.position, Time.deltatime * speed);
这行代码中,Lerp()函数返回一个自身位置和target位置之间的一个位置,比例是Time.deltatime * speed,然后再把这个值作为自己的新位置
如果第三个参数是0.5,自身位置为0,目标位置为10,那么第一次自身从0移动到5,第二次从5移动到7.5,即每次都会移动(目标位置 - 自身位置)* 0.5的位置,由于自己越来越接近目标位置,这个值也会越来越小,所以每次往前移动的距离也就越来越小,这样就实现了弹性的效果。
当然,从数学的角度来看,只能无限接近目标位置,永远也到达不了目标位置,但是玩家是感觉不出这一点的差距的。
四、使用增量时间进行插值
最后回到本篇的重点,为什么在插值函数中要使用增量时间作为参数呢?
还是以最简单的数学插值为例
a = Mathf.Lerp(a, b, 0.1f);
每次运行后,a都会以10%的速度向b靠近。假设a和b之间相差1个单位,第一帧后,a和b之间剩余的距离变为0.9,第二帧过后,a和b之间剩余的距离变为0.81 = 0.9 * 0.9。以此类推,第n帧过后,a和b之间的剩余距离变为0.9^n
如果FPS=10,那么一秒后a和b之间的剩余距离变为0.9^10,如果如果FPS=20,那么一秒后a和b之间的剩余距离变为0.9^20,也就是说插值效果和电脑运行的帧率有关。
下面考虑使用增量时间的情况(一般会用speed来乘以增量时间,这里为了简化就假设speed为1)
a = Mathf.Lerp(a, b, Time.deltatime);
类似的,在n帧过后,a和b之间的剩余距离变为 (1 - Time.deltatime) ^ n,如果假设电脑帧率稳定的话,根据增量时间的定义,Time.deltatime表示每帧运行的事件,即Time.deltatime= 1/n
那么,a和b之间的剩余距离变为 (1 - 1/n) ^ n。可以看出,插值效果仍然和帧率有关,但是如果带入数字详细计算的话,会发现实际差距已经很小。
例如,n = 30,即FPS=30,那么结果大致是0.36166,如果 n = 60,结果大致是0.36479
这种写法比较简便,而且不同帧率下的插值效果相差很小,这也是为什么大部分代码都会这么写的原因。
最后,给出如下写法:
a = Mathf.Lerp(a, b, 1 - speed ^ Time.deltatime);
通过同样的计算可得,a和b之间的剩余距离变为 [1 - (1 - speed ^ (1/n) ] ^ n = speed,这种写法做到了完全和帧率无关,即无论在哪一台电脑上运行,在相同的时间后都会有相同的插值效果
五、总结
在不苛求完美的情况下,一般采取第二种写法,就可以取得较好的插值效果效果
参考文章:https://www.construct.net/en/blogs/ashleys-blog-2/using-lerp-delta-time-924
Unity插值函数Lerp()与增量时间Time.deltatime的更多相关文章
- Time.deltaTime 增量时间
static var deltaTime : float Description描述 The time in seconds it took to complete the last frame (R ...
- Unity学习疑问记录之时间变量
1.Time.deltaTime 以秒计算,完成最后一帧的时间 放在Update()函数中的代码是以帧来执行的.如果我们需要物体的移动以秒来执行.我们需要将物体移动的值乘以Time.deltaTime ...
- Unity的Lerp函数实现缓动
在Unity里面Lerp函数可以实现缓动效果 下面例子实现点光源的移动 在场景中创建好一个平面,一个点光源,我在这里随便放了一个模型. 然后新建c#脚本,代码如下: using UnityEngine ...
- Time.fixedDeltaTime 固定增量时间
static var fixedDeltaTime : float Description描述 The interval in seconds at which physics and other f ...
- Unity通过NTP获取网络时间
最初通过qq时间服务器获得时间,经常出现有网络也获取失败的情况. 后面寻找解决办法,查找资料终于发现通过ntp时间服务器获取网络时间的方法. 首先游戏开始获得初始化网络时间,通常只获取一次,其他时 ...
- Unity 新手入门 如何理解协程 IEnumerator yield
Unity 新手入门 如何理解协程 IEnumerator 本文包含两个部分,前半部分是通俗解释一下Unity中的协程,后半部分讲讲C#的IEnumerator迭代器 协程是什么,能干什么? 为了能通 ...
- Unity中Time.deltaTime的含义及其应用
The time in scenes it took to complete the last frame.这是使用此函数的时候给出的提示 一般我们会在设置速度的时候看到这个函数.先写出我对Time. ...
- 如何正确的使用Lerp In Unity
摘要 本文探讨如何用lerp实现近似的匀速旋转,当然如果运用本文给出的方法,使用slerp则可以实现匀速旋转,并指出Unity官方lerp示例代码的一些缺陷. 现有问题 比如四元数Lerp API: ...
- kettle 6.1 按时间循环增量抽取数据
场景:假设有一张表数据量很大,需要按一个时间来循环增量抽取 方法:主要是通过JOB自身调用,实现循环调用,类似于 函数自调用 的循环. 1.JOB全图: 2.获取增量时间,并设置增量时间环境变量 3. ...
随机推荐
- AJAX核心XMLHTTPRequest对象
老早就写好了总结.今天整理发表一下. XMLHttpRequest对象是AJAX的核心技术,XMLHttpRequest 是XMLHTTP 组件的对象,通过这个对象.AJAX能够像桌面应用程序一样仅仅 ...
- 项目Alpha冲刺(团队9/10)
项目Alpha冲刺(团队9/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...
- (转载)解决MySql 数据库 提示:1045 access denied for user 'root'@'localhost' using password yes
今天想用用MySQL 数据库 谁知道老提示 1045 access denied for user 'root'@'localhost' using password yes 最后在csdn 上找到 ...
- huawei校招测试题
三道题两小时. 第一题,圈住所有点的长方形,很简单略过. 第二题:奇偶排序. 奇偶排序 描述: 输入若干(不超过1000个)非负整数数字,请先取出为奇数的数字按从大到小排序,再取出偶数从小到大进行排序 ...
- JavaScript重点记忆
String的常用方法 indexOf() 返回字符串中检索指定字符第一次出现的位置 lastIndexOf() 返回字符串中检索指定字符最后一次出现的位置 match() 找到一个或多个正则表达式的 ...
- HDOJ 5045 Contest
状压DP.. . . Contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- 在无代码文件的aspx文件中添加类、函数和字段的方法
大家都知道,在开始WebForm程序时,一个WebForm由.cs代码文件与.aspx页面文件组成.在aspx文件中可以嵌入C#代码,但无法在aspx的嵌入C#代码中定义类,函数和字段等.这样,就限制 ...
- android 提示
1.Toast: Toast toast=new Toast(context); Toast.makeText(context, text, duration);//返回值为Toast toast.s ...
- 对 block 内存管理的一些看法
首先交代一下retain cycle ,和 产生retain cycle后我们应该怎么处理. 1.retain cycle在block中是极易产生,block就是一段可以灵活使用的代码,你可以把它当做 ...
- codeforcfes Codeforces Round #287 (Div. 2) B. Amr and Pins
B. Amr and Pins time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...