This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.
Lerp的误解和正确使用
Unity中由于Lerp
方法用于在两个值之间进行线性插值,但是常见的用法往往是错误的。比如该例使用Lerp旋转的用法:
1 | using UnityEngine; |
实际上,作者也指出该方法存在以下三个问题,
- 这样的旋转不是匀速的旋转,这种是逐渐减速的旋转。
- 永远无法旋转到目标角度,可以无限的接近。
- 旋转速度与帧数相关,请注意from.rotation在变化,举例来说单位时间内移动2次2%和移动1次4%并不相同。
想要正确使用Lerp(线性插值),我们需要预先保存起始阶段和目标阶段的角度、位置等,取决于我们如何使用Lerp。
1 | private Vector3 endPosition = new Vector3(1f,1f,1f); |
使用以上代码就能够正确使用Lerp进行线性插值了。可见其要点在于不要在插值过程中输入改变后的起始位置。许多人使用实时更新的起始位置,目的是为了实现逐渐减速的移动过程,尽管肉眼上是可行的,但会面临前例出现的三个问题,即不是匀速转动——这是可以我们的目的,永远无法到达目标位置/角度——这是一个隐藏的问题,往往需要进行额外的判定,比如,当位置与目标位置的差值小于某阈值后停止插值等,实际上让代码变得更加复杂了。旋转速度与帧数相关——同样是个问题,特别是面临高性能机器的时候。
实际上,我们可以用以下的方法实现逐渐减速的移动、旋转效果:
1 | transfrom.position = Vector3.Lerp(startPosition, endPosition, Mathf.SmoothStep(0, 1, percentageComplete)); |
在这里,我们使用了Mathf.SmoothStep()方法来让平滑我们的percentageComplete变量,我们可以选用任何我们想要的方法,比如Math.pow(percentage, 0.5)
。通过这种方法实现的旋转和平移不受帧率的影响,并且更加可靠。
利用动画曲线实现
为了实现更加可控的曲线,我们可以使用动画曲线。
1 | [SerializeField] private AnimationCurve curve; // 我们只需要在编辑器中设定该值即可。 |
同时将Lerp的输入修改为:
1 | transfrom.position = Vector3.Lerp(startPosition, endPosition, curve.Evaluate(percentageComplete)); |
即可实现功能。
#Unit #Lerp
参考
https://www.youtube.com/watch?v=MyVY-y_jK1I
blueraja.com/blog/404/how-to-use-unity-3ds-linear-interpolation-vector3-lerp-correctly