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. ...
随机推荐
- 【转载】一致性哈希算法(consistent hashing)
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...
- Erlang进程堆垃圾回收机制
原文:Erlang进程堆垃圾回收机制 作者:http://blog.csdn.net/mycwq 每一个Erlang进程创建之后都会有自己的PCB,栈,私有堆.erlang不知道他创建的进程会用到哪种 ...
- CF 535c Tavas and Karafs
Tavas and Karafs Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u S ...
- 项目Alpha冲刺(团队9/10)
项目Alpha冲刺(团队9/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...
- 每日五题(Spring)
1使用Spring框架的优点是什么? 控制反转: Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们. 面向切面的编程(AOP): Spring支持面向切面的编 ...
- 2016/06/09 ThinkPHP3.2.3使用分页
效果图:
- gcc 头文件是用户应用程序和函数库之间的桥梁和纽带 功能的真正逻辑实现是以硬件层为基础
gcc GCC, the GNU Compiler Collection - GNU Project - Free Software Foundation (FSF) http://gcc.gnu.o ...
- Oracle Exception
Oracle存储过程的异常处理 1.为了提高存储过程的健壮性,避免运行错误,当建立存储过程时应包含异常处理部分.2.异常(EXCEPTION)是一种PL/SQL标识符,包括预定义异常.非预定义异常和自 ...
- Android cookies正确的更新方式
之前的更新方式 一搜cookies的使用,非常easy搜到非常多文章.主要的几步大致同样.例如以下图: 基本上都要求大家先调用cookieManager.removeAllCookie()或者调用 c ...
- poj 2559 Largest Rectangle in a Histogram 栈
// poj 2559 Largest Rectangle in a Histogram 栈 // // n个矩形排在一块,不同的高度,让你求最大的矩形的面积(矩形紧挨在一起) // // 这道题用的 ...