在unity3d中经常用线性插值函数Lerp()来在两者之间插值,两者之间可以是两个材质之间、两个向量之间、两个浮点数之间、两个颜色之间,其函数原型如下:

1.Material.Lerp 插值

function Lerp(start : Material, end : Material, t : float) : void

在两个材质之间插值

2.Vector2.Lerp 插值

static functionLerp (from : Vector2, to : Vector2, t : float) : Vector2

两个向量之间的线性插值。按照数字t在form到to之间插值。

t是夹在0到1之间。当t=0时,返回from。当t=1时,返回to。当t=0.5时放回from和to之间的平均数。

3.Vector3.Lerp 插值

static functionLerp (from : Vector3, to :Vector3, t : float) :Vector3

两个向量之间的线性插值。按照数字t在from到to之间插值。

4.Vector4.Lerp 插值

static functionLerp (from : Vector4, to : Vector4, t : float) : Vector4

两个向量之间的线形插值。按照数字t在from到to之间插值。t是夹在[0…1]之间的值。,当t = 0时,返回from。当t = 1时,返回to。当t = 0.5 返回from和to的平均数。

5.Mathf.Lerp 插值

static functionLerp (from : float, to : float, t : float) : float

基于浮点数t返回a到b之间的插值,t限制在0~1之间。当t = 0返回from,当t = 1 返回to。当t = 0.5 返回from和to的平均值。

6.Color.Lerp 插值

static functionLerp (a : Color, b : Color, t : float) : Color

通过t在颜色a和b之间插值。

"t"是夹在0到1之间的值。当t是0时返回颜色a。当t是1时返回颜色b。

插值,从字面意思上看,就是在其间插入一个数值,这种理解是否正确呢?我们先从最简单的浮点数插值函数来分析:

Mathf.Lerp 插值

static functionLerp (from : float, to : float, t : float) : float

基于浮点数t返回a到b之间的插值,t限制在0~1之间。当t = 0返回from,当t = 1 返回to。当t = 0.5 返回from和to的平均值。

首先,我们来做一个试验,启动Unity3D,任建一个脚本文件,在其Start()中输入内容如下:

void Start () {

print(Mathf.Lerp(0.0f, 100.0f,0.0f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.1f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.2f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.3f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.4f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.5f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.6f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.7f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.8f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,0.9f).ToString());

print(Mathf.Lerp(0.0f, 100.0f,1.0f).ToString());

}

运行Unity,在控制台将打印出:

这个实验是在0到100之间插值,插入什么值,取决于第3个参数,从打印结果可看出,第3个参数是个比例因数,是0.1时表示0到100这个长度的十分之一,同理,0.2表示十分之二,依此类推。从这点上看来,我们起初从字面上所理解的插值就是插入一个数值是可以这样理解的。

如果我们把上面那个脚本里的插值函数里的第一个参数变为100.0f,第二个参数变为110.0f,第三个参数保持不变,大家想想其运行结果该是什么呢?可不要认为是0、1、2、3、4、5、6、7、8、9、10了哟,实际结果是100、101、102、103、104、105、106….,因插值是把值插在原来的两数之间,这说明这个函数首先是根据第三个参数所给定的比例算出净增量,再加上起始数,最终算出插值值的。

在unity3d游戏开发中,应用最多的是Vector3.Lerp 向量插值,下面我们以此插值来猜推其内部实现机理以及一些应用。

如图,在空间中存在两点A(0,10,0)与B(10,0,-10),我们在A、B两点间插入一C点,假设C点的位置在AB的五分之二处,即AC/AB=0.4,根据相似图形对应边成比例的初中几何知识可知,在⊿ABO中AC/AB=OD/OB,同理在⊿OBF中OD/OB=OE/OF,所以AC/AB=OD/O=OE/OF = 0.4,则C点的X坐标值为:OE=0.4*OF=0.4*10=4。

根据上图,还可知ED/FB=0.4,所以C点的Z坐标值DE=0.4*BF=0.4*(-10)=-4。

C点的Y坐标值请看下图:

EO/AO=DF/AF=CB/AC=1-0.4=0.6,则C点的Y坐标值EO=0.6*AO=0.6*10=6。

综上所述,C点的三维坐标为C(4,6,-4)。

下面我们利用Unity3D中的Vector3.Lerp 插值函数:static function Lerp (from :Vector3, to :Vector3, t : float) :Vector3来计算上面演算的插值。

我们把先前脚本中的Start()函数改写成:

void Start()

{ print(Vector3.Lerp(newVector3(0, 10, 0),newVector3(10, 0, -10), 0.4f).ToString()); }

其运行结果为:

这与我们的演算结果是一致的。

上面的演算,我们为了简便,A、B两点取得较特殊,降低了演算的复杂度。而对普通的A、B两点,如下图所示:

我们同样可以得到三角形EGL与三角形EFK,使用同样的方法可计算出HI的长度,再加上OH的长度就是C点的X坐标值了。同样的方法可推演出Y与Z的坐标。手工计算是很复杂的,而Lerp函数可以高效地为我们返回这个插值的,我们在这里做出的演算,只是帮助我们来推测Lerp这个函数的内部实现机理而也,实际运用中,一切工作都是交Lerp函数去完成。

Lerp函数在游戏开发过程使用较多,在Unity的帮助文档里就有为我们列举了Vector3.Lerp的两个应用的例子,一个是在1秒时间动画位置移动从start.position开始到end.position结束:

[csharp]  view plain  copy

print?

  1. using UnityEngine;
  2. usingSystem.Collections;
  3. public classexample : MonoBehaviour
  4. {
  5. public Transform start;
  6. public Transform end;
  7. void Update()
  8. {
  9. transform.position =Vector3.Lerp(start.position, end.position, Time.time);
  10. }
  11. }

另一个例子:

//像弹簧一样跟随目标物体

[csharp]  view plain  copy

print?

  1. using UnityEngine;
  2. usingSystem.Collections;
  3. public classexample : MonoBehaviour
  4. {
  5. public Transform target;
  6. public float smooth = 5.0F;
  7. void Update()
  8. {
  9. transform.position =Vector3.Lerp(transform.position, target.position, Time.deltaTime * smooth);
  10. }
  11. }

这个例子中的transform.position是去跟随的那个物体的空间坐标,target.position是目标物体的空间坐标,整句的结果是让跟随物体的坐标不断地变化为它们两者之间的插值,然而随着时间的推移,第三个参数的值最终会为1,所以最终跟随物体的位置会与目标物体重合的。我们以前所玩的游戏中,主人公身上依附着一只宠物如鹰,主人公移动时,鹰会跟随着飞动,主人公移动得快它就飞行跟动得快,始终不会离开主人公,使用Lerp插值函数就可实现。

下面我们来看另一个应用实例。

这是酷跑游戏场景,囚犯沿着一条森林道路向前奔跑,后面有警车追赶,前面有路障,在游戏过程中,我们要在囚犯奔跑的固定路线上随机产生路障,而道路不是平直的,既左右弯曲,又上下起伏,由程序随机生成的路障怎样确定其空间位置呢?这时,Lerp函数就派上了用场。

先根据道路的弯曲与起伏,在转折处设置一个空物体,此空物体的Position值即空间坐标与此处道路一致,我们把这些空物体所在的点称为道路转折点,这些点连接而成的线段所组成的多段折线贴合在路面上,是这条道路的近似路径,这些点取得越多、越准确,这条路径与道路的相似程度就越高。

现在我们用那条路径来代替那条道路,把随机产生的路障放在这条路径上也就是放在道路上了。

假设我们想每隔100米至200米之间产生一个路障,用变量z += Random.Range(100, 200)记录下该路障的Z坐标值(因囚犯总体上是沿着Z轴往前跑)然后根据此Z坐标值判断该坐标值在前面所设置的转折点中的哪两个点之间,找到后就在这两个点之间插值,其插值的比例因数(Lerp()函数的第3个参数)可由两个转折点与这个插值点这三个点中已知的Z坐标值算出来,这样Vector3.Lerp (from : Vector3, to :Vector3, t : float)函数中的三个参数值便都是已知的了,它就可计算出这个插值点的空间坐标了,根据前面的设计,这两个转折点之间的线段是贴合在路面上的,那么此插值的坐标也就是在路面上了,根据此插值放置的路障也就不会偏离道路,且会随着道路的左转而左转,右转而右转,上坡而上坡,下坡而下坡了。

具体设计过程如下:

导入道路模型,假设命名为forest_1。模型设计时就确定好了其长度为3000、坐标原点在其终端上了的。导入后我们将其沿Z轴正方向放置在场景中,让其Transorm.Position的X、Y值均为0。我们可以导入多段同类型的道路模型,通过控制它们的Z值来把它们拼接成长长的森林道路。

在此道路物体上新建一个空物体作为它的子物体,命名为waypoint,再在其下建立多个为空的空物体,分别命名为waypoint_01、waypoint_02……,把它们放在道路的转折处,并通过放大、旋转场景图后细调这些孙物体的坐标值,使它们与道路路面贴合,如下图所示:

说明:图中的绿色按钮状块就是这些空物体,因它们是空物体,不能显示在场景中,是通过属性面板给它们设置了一个供编辑时显示使用的图标标示。

这样,我们便把弯弯曲曲的道路分成了一段一段的直路段,并记录下来了各段路段两端的特征点的坐标值。有了这些特征点,也就有了与道路相近的路线了。这是化曲为直的方法,把弯曲、起伏的道路化成了与此相近的一段一段的线段。这样的点越多,其相似程度越高。

在waypionts上创建一个脚本组件waypionts.cs:

[csharp]  view plain  copy

print?

  1. using UnityEngine;
  2. using System.Collections;
  3. public class waypoints : MonoBehaviour
  4. {
  5. public Transform[] points;
  6. void OnDrawGizmos()
  7. {
  8. iTween.DrawPath (points);
  9. }
  10. }

public Transform[]points;该句所定义的points就是存放那些特征点的数组,因它是public,可在Unity编辑界面中为其赋值,其操作方法是先在Hierarchy视图中选中waypoints控件,然后在其Inspector视图中点击图标锁住其Inspector面板,然后在Hierarchy视图中全选waypoint_01至waypiont_11后拖到属性面板上的数组名points上即可完成赋值,如下图:

接下来,在这个森林道路上建立的Forestcs.cs脚本组件里添加生成路障的脚本:

[cpp]  view plain  copy

print?

  1. <span style="background-color: rgb(255, 255, 153);">using UnityEngine;
  2. using System.Collections;
  3. public class Forest : MonoBehaviour
  4. {
  5. public GameObject[] obstacles;     //路障物体数组
  6. public float startLength = 50;   //路障在道路上出现的开始位置
  7. public float minLength = 100;   //路障距上一个路障的最小距离
  8. public float maxLength = 200;   //路障距上一个路障的最大距离
  9. private Transform player;        //游戏主人公-奔跑者的Transform组件
  10. private waypoints wayPoints;    //与路面相贴合的路线上的脚本组件
  11. void Awake()
  12. {
  13. player = GameObject.FindGameObjectWithTag(Tags.player).transform; //找到游戏主人公-奔跑者并获得它的Transform组件
  14. wayPoints = transform.Find("waypoints").GetComponent<waypoints>();  //找到与路面相贴合的路线上的脚本组件
  15. }
  16. // Use this for initialization
  17. void Start()
  18. {
  19. GenerateObstacle();    //当森林道路被创建出来时,就会自动调用此Start()方法,从而调用此GenerateObstacle()方法
  20. }
  21. // 如果主人公跑完了这段道路,则通知GenerateForest类开始运行产生新的道路,并销毁已跑完的这条道路
  22. void Update ()
  23. {
  24. if (player.position.z > transform.position.z+100)
  25. {
  26. Camera.main.SendMessage("GenerateForest");
  27. GameObject.Destroy(this.gameObject);
  28. }
  29. }
  30. void GenerateObstacle()
  31. {
  32. float startZ = transform.position.z - 3000;  //当前道路在场景中的起始Z坐标
  33. float endZ = transform.position.z;          //当前道路在场景中的结束Z坐标
  34. float z = startZ + startLength;             //将要产生的路障的Z坐标
  35. while (true)
  36. {
  37. z += Random.Range(100, 200);            //每隔100多米的距离产生一个路障
  38. if (z > endZ)                           //如果将要产生路障的位置超出了这条道路则退出路障产生循环,否则产生路障
  39. {
  40. break;
  41. }
  42. else
  43. {
  44. Vector3 position = GetWayPosByz(z);                    //调用GetWayPosByz()方法计算路障位置坐标
  45. int obsIndex = Random.Range(0, obstacles.Length);      //产生一个从路障数组里取路障的随机序数
  46. GameObject.Instantiate(obstacles[obsIndex], position, Quaternion.identity);//实例化路障
  47. }
  48. }
  49. }
  50. Vector3 GetWayPosByz(float z)
  51. {
  52. Transform[] points = wayPoints.points;       //在道路上设置的转折点的集合
  53. int index = 0;                               //转折点在集合中的序数号
  54. for (int i = 0; i < points.Length-1; i++)
  55. { //根据要插入路障的Z值在集合中寻找在哪两个点之间,找到后记下序数号
  56. if(z<=points[i].position.z && z>=points[i+1].position.z){
  57. index = i;
  58. break;
  59. }
  60. }
  61. //使用Lerp函数计算出插入路障处的空间坐标值
  62. return Vector3.Lerp(points[index + 1].position, points[index].position,(z - points[index + 1].position.z) / (points[index].position.z - points[index +1].position.z));
  63. }
  64. }</span>

unity中mathf.Lerp的运用相关推荐

  1. Unity中Mathf.Lerp的用法

    教程地址: https://learn.unity.com/tutorial/linear-interpolation?language=en&projectId=5c8920b4edbc2a ...

  2. Unity中的Lerp函数

    Lerp(a,b,f) 函数的公式是 返回 (1-f)*a+b*f  所以当f为0时返回的是a  f为1时 返回的是b  所以第三个参数应该是取一个 0~1的渐变值 例如要将角色从一个位置用lerp移 ...

  3. unity中使用手柄控制角色移动

    unity中第三人称下使用手柄控制角色移动 本文建议结合这一篇文章观看: https://blog.csdn.net/qq_45919090/article/details/109393562 uni ...

  4. Unity中单点和多点触控

    Input.touchCount获取当前的触摸点数目,若为1则是单点触控,大于1则是多点触控 点击事件用:Input.GetTouch(num).phase== TouchPhase.Began这样的 ...

  5. Unity中的一些重要函数和类的解析

    下面的这些函数在Unity3d程序开发中具有很重要的作用. Update 当MonoBehaviour启用时,其Update在每一帧被调用. LateUpdate 当Behaviour启用时,其Lat ...

  6. SiKi学院 Unity中常用api学习笔记(015-019)

    Api 应用程序编程接口 前言 笔记是看siki学院中<Unity中常用api>的学习笔记 课程地址:  http://www.sikiedu.com/my/course/59 强烈推荐大 ...

  7. 一种城市道路网络的随机生成方式(Unity中可视化)

    一种城市道路网络的随机生成方式(Unity中可视化) 1. 说在开头 2. 有限元网格划分 2.1. 什么是有限元 2.2. 前沿推进法/波前推进法(Advancing Front Technique ...

  8. unity中的缓动插值曲线,Easing Curves的那些事

    这个地址是一个可以查看各种插值效果的 flash demo http://robertpenner.com/easing/easing_demo.html 现在浏览器都不支持flash插件了,补个图吧 ...

  9. 【Unity3D Shader编程】之五 圣诞夜篇 Unity中Shader的三种形态对比 混合操作合辑

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

最新文章

  1. SAP RETAIL供应商寄售库存跨公司转移后的库存状况
  2. Spring mvc集成log4j2
  3. HDU1533 Going Home(最小费用最大流 spfa模版)
  4. 怎么设置html页面背景图片大小怎么设置,HTML – 响应式网页设计:“如何根据浏览器窗口大小使用CSS调整背景图像的大小”?...
  5. python set()函数讲解
  6. Vue学习笔记入门篇——数据及DOM
  7. 关于Stop The World的几个问题
  8. 关于Python切片的问题,从左向右提取元素与从右向左提取元素
  9. MySQL使用注意事项(一)
  10. SQLServer的索引和统计
  11. VMware 配置虚拟机端口映射,实现局域网络互相访问
  12. 初学者指南:为开源做贡献
  13. wps怎么下载仿宋gb2312_仿宋gb2312字体官方下载
  14. 超星阅读器pdz文件打印转pdf文件
  15. matlab_多目标遗传算法
  16. 边境的悍匪—机器学习实战:第三章 分类
  17. Markdown 图片排版
  18. 求简单多边形面积时非常有用的“鞋带公式”
  19. Linux 文件内容查看
  20. php js 对象追加元素,JS添加元素新节点

热门文章

  1. 即将举行的Live From Redmond免费网络广播讲座
  2. 不懂带人就自己累到死:带团队1核心、4重点、6角色、10注意
  3. display: inline-block换行问题
  4. 奥比中光 ORBBEC Astra Mini Pro简单使用
  5. android穿山甲广告位id,Android自渲染Draw广告
  6. ZZULIOJ 1011: 圆柱体表面积(C/C++)
  7. android 地铁地图api,利用高德地图api绘制公交+地铁的等时圈
  8. 解决告警“warning #1295-D Deprecated declaration xxxxxxx - give arg types”方法
  9. 敏捷神话1:“敏捷是一种方法论”
  10. NodeJS 发送 POST 请求 curl -d JS 类的静态属性使用