Version: 6000.3
语言: 中文
数学编程
使用常用数学函数

使用矢量移动对象

向量是一个基本的数学概念,它允许您描述方向和大小。在游戏和应用程序中,向量通常用于描述基本属性,例如角色的位置、物体移动的速度或两个对象之间的距离。

矢量算术是计算机编程许多方面的基础,例如图形、物理和动画,深入了解它对于充分利用 Unity 非常有用。

向量可以在多维度上表示,Unity 提供了用于处理 2D、3D 和 4D 向量的 Vector2、Vector3 和 Vector4 类。 这三种类型的 Vector 类都共享许多相同的函数,例如大小,因此除非另有说明,否则本页上的大多数信息都适用于所有三种类型的 Vector。

本页概述了 Vector 类及其在编写脚本时的常见用途。有关向量类的每个成员的详尽参考,请参阅 Vector2Vector3Vector4 的脚本参考页面。

了解向量算术

加法

当两个向量相加时,结果相当于将原始向量作为“步骤”,一个接一个。请注意,两个参数的顺序无关紧要,因为无论哪种方式结果都是相同的。

向量 a 是具有 x 分量 3 和 y 分量 5 的 2D 向量。向量 b 是具有 x 分量 2 和 y 分量 -1 的 2D 向量。将 a 和 b 相加将得到向量 c,这是一个具有 x 分量 5 和 y 分量 4 的 2D 向量。三个向量与原点的关系形成一个不等边三角形。
向量 a 是具有 x 分量 3 和 y 分量 5 的 2D 向量。向量 b 是具有 x 分量 2 和 y 分量 –1 的 2D 向量。将 a 和 b 相加将得到向量 c,这是一个具有 x 分量 5 和 y 分量 4 的 2D 向量。三个向量与原点的关系形成一个不等边三角形。

如果第一个向量被当作空间中的一个点,那么第二个向量可以解释为从该位置的偏移或“跳跃”。例如,要查找地面上某个位置上方 5 个单位的点,可以使用以下计算:

 var pointInAir = pointOnGround + new Vector2(0, 5);

如果向量代表力,那么根据它们的方向和大小来考虑它们会更直观(大小表示力的大小)。添加两个力向量将产生一个与力组合相等的新向量。当同时作用多个独立组件时施加力时,这个概念通常很有用(例如,向前推进的火箭也可能受到侧风的影响)。

此处的示例使用 2D 矢量,但相同的概念适用于 3D 和 4D 矢量。

减法

矢量减法最常用于获取从一个对象到另一个对象的方向和距离。请注意,两个参数的顺序对于减法很重要:

从 2D 向量 b 中减去 2D 向量 a,得到 x 分量为 5 和 y 分量 4 的 2D 向量。这被说明为从点 a 点到 b 点的带有方向箭头的单线。
从 2D 向量 b 中减去 2D 向量 a,得到 x 分量为 5 和 y 分量 4 的 2D 向量。这被说明为从点 a 点到 b 点的带有方向箭头的单线。
// The vector d has the same magnitude as c but points in the opposite direction.
var c = b - a;
var d = a - b;

与数字一样,将向量的负数相加与减去正数相同。

// These both give the same result.
var c = a - b;
var c = a + -b;

向量的负数与原始矢量具有相同的大小,并且指向同一条线,但方向完全相反。

从一个物体到另一个物体的方向和距离

如果空间中的一个点从另一个点中减去,那么结果是一个从一个对象“指向”另一个对象的向量:

// Gets a vector that points from the player's position to the target's.
var heading = target.position - player.position;

除了指向目标物体的方向外,该向量的大小也等于两个位置之间的距离。您可能需要一个“归一化”向量来给出目标的方向,但距离是固定的(例如用于引导射弹)。您可以通过将向量除以自己的大小来归一化向量:

var distance = heading.magnitude;
var direction = heading / distance; // This is now the normalized direction.

这种方法比单独使用大小和归一化属性更可取,因为它们都非常耗费 CPU(它们都涉及计算平方根)。

如果您只需要使用距离进行比较(例如,用于邻近度检查),那么您可以完全避免大小计算。这sqrMagnitude属性给出了大小值的平方,并且与大小一样计算,但没有耗时的平方根运算。您可以将大小的平方与距离的平方进行比较,而不是将大小与已知距离进行比较:

if (heading.sqrMagnitude < maxRange * maxRange) {
    // Target is within range.
}

这比在比较中使用真实幅度要有效得多。

有时,在 3D 中工作时,您可能需要一个指向目标的“地面航向”。例如,想象一个玩家站在地上,需要接近漂浮在空中的目标。如果从目标的位置中减去玩家的位置,则生成的向量将向上指向目标。这不适合调整玩家的变换方向,因为它们也会指向上方;真正需要的是从玩家位置到目标正下方地面位置的向量。您可以通过获取减法结果并将 Y 坐标设置为零来获得此值:

var heading = target.position - player.position;
heading.y = 0;  // This is the overground heading.

标量乘法和除法

在讨论向量时,通常将普通数字(例如浮点数)称为标量。这样做的意思是,标量只有“尺度”或大小,而向量同时具有大小和方向。

将向量乘以标量会得到指向与原始方向相同的向量。但是,新向量的大小等于原始大小乘以标量值。

同样,标量除法将原始向量的大小除以标量。

当矢量表示运动偏移或力时,这些作非常有用。它们允许您在不影响其方向的情况下更改矢量的大小。

当任何向量除以其自身的大小时,结果是大小为 1 的向量,称为归一化向量。如果归一化向量乘以标量,则结果的大小将等于该标量值。当力的方向恒定但强度可控时(例如,来自汽车车轮的力总是向前推动,但动力由驾驶员控制),这很有用。

点积

点积采用两个向量并返回一个标量。该标量等于两个向量的大小相乘,结果乘以向量之间角度的余弦。当两个向量都归一化时,余弦本质上表示第一个向量在第二个向量方向上延伸多远(反之亦然 - 参数的顺序无关紧要)。

两个表示为方向线的二维矢量从同一原点延伸。向量 a 笔直向上延伸,具有正 y 分量,但没有 x 分量。向量 b 向上延伸比向量 a 更小的 y 分量,并向右延伸正 x 分量。描述两个向量覆盖的 y 轴区域的线被标记为 a 乘以 b。
两个表示为方向线的二维矢量从同一原点延伸。向量 a 笔直向上延伸,具有正 y 分量,但没有 x 分量。向量 b 向上延伸比向量 a 更小的 y 分量,并向右延伸正 x 分量。描述两个向量覆盖的 y 轴区域的线被标记为 a 乘以 b。

下面您可以看到不同角度的向量与参考向量相比如何返回 1 和 –1 之间的点积值的比较:

一系列向量从参考向量以 0 到 180 度之间的角度向外辐射。在与参考向量的 0 到 90 度之间,点积在 1 和 0 之间,并随着角度的增加而减小。在与参考向量成 90 到 180 度之间,点积在 0 和 -1 之间,并随着角度的增加而减小。
一系列向量从参考向量以 0 到 180 度之间的角度向外辐射。在与参考向量的 0 到 90 度之间,点积在 1 和 0 之间,并随着角度的增加而减小。在与参考向量的 90 到 180 度之间,点积在 0 和 –1 之间,并随着角度的增加而减小。

点积在数学上比计算余弦更简单,因此可以用它来代替Mathf.Cos函数或矢量幅度运算(它不会做完全相同的事情,但有时效果是等效的)。然而,计算点积函数需要更少的 CPU 时间,因此它可能是一个有价值的优化。

如果要计算一个向量位于另一个向量方向的大小的量,点积非常有用。

例如,汽车的车速表通常通过测量车轮的转速来工作。汽车可能不会直接向前移动(例如,它可能会侧向打滑),在这种情况下,部分运动不会在汽车所面向的方向上 - 因此不会被车速表测量。对象的rigidbody.velocityvector 将给出其整体运动方向的速度,但要隔离正向速度,您应该使用点积:

var fwdSpeed = Vector3.Dot(rigidbody.velocity, transform.forward);

方向可以是你喜欢的任何方向,但对于此计算,方向向量必须始终归一化。结果不仅比速度的大小更准确,而且还避免了查找大小所涉及的缓慢平方根运算。

矢积

叉积仅对 3D 矢量有意义。它接受两个 3D 向量作为输入,并返回另一个 3D 向量作为其结果。

结果向量垂直于两个输入向量。您可以使用“右旋螺丝规则”从输入向量的顺序中记住输出向量的方向。如果可以按照输入向量的顺序卷曲手指,则拇指指向输出向量的方向。如果参数的顺序颠倒,则生成的向量将指向完全相反的方向,但大小相同。

结果的大小等于输入向量的大小相乘,然后该值乘以它们之间角度的正弦。正弦函数的一些有用值如下所示:-

一系列向量从参考向量以 0 到 180 度之间的角度向外辐射。在与参考矢量成 0 到 90 度之间,叉积介于 0 和 1 之间,并随着角度的增加而增加。在与参考向量的 90 到 180 度之间,叉积在 1 和 0 之间,并随着角度的增加而减小。
一系列向量从参考向量以 0 到 180 度之间的角度向外辐射。在与参考矢量成 0 到 90 度之间,叉积介于 0 和 1 之间,并随着角度的增加而增加。在与参考向量的 90 到 180 度之间,叉积在 1 和 0 之间,并随着角度的增加而减小。

叉积可能看起来很复杂,因为它在其返回值中结合了几个有用的信息。然而,与点积一样,它在数学上非常有效,可用于优化代码,否则这些代码将依赖于较慢的超越函数,例如正弦和余弦。

计算法向/垂直向量

在期间经常需要“法线”向量(即垂直于平面的向量)meshUnity 的主要图形原语。网格体构成了 3D 世界的很大一部分。Unity 支持三角或四边形多边形网格。Nurbs、Nurms、Subdiv 曲面必须转换为多边形。更多信息
请参阅术语表
生成,在路径跟踪和其他情况下也很有用。给定平面中的三个点,比如网格三角形的角点,你可以按如下方式找到法线:

  • 从三个点中选择一个
  • 分别从其他两个点中减去它(生成两个新向量,“Side 1”和“Side 2”)
  • 计算向量“侧 1”和“侧 2”的叉积
  • 叉积的结果是一个垂直于三个原始点所在的平面的新向量 - “法线”。
三分;a、b 和 c 在 3D 坐标空间中形成三角形的角点。从 a 中减去 b 和 c 的向量给出了三角形的长边,从 a 到 b 的边 1 和从 a 到 b 的边 2。向量边 1 和边 2 的叉积给出一个垂直于三个原始点所在平面的新向量。
三分;a、b 和 c 在 3D 坐标空间中形成三角形的角点。从 a 中减去 b 和 c 的向量给出了三角形的长边,从 a 到 b 的边 1 和从 a 到 b 的边 2。向量边 1 和边 2 的叉积给出一个垂直于三个原始点所在平面的新向量。
Vector3 a;
Vector3 b;
Vector3 c;

Vector3 side1 = b - a;
Vector3 side2 = c - a;

Vector3 normal = Vector3.Cross(side1, side2);
左手演示了用于确定用于计算叉积的向量的输入顺序的左手规则。食指和拇指彼此呈直角伸展,而中指在第三个平面上与食指成直角伸展。食指和拇指分别代表叉积计算的第一和第二输入向量。中指表示生成的法线。
左手演示了用于确定用于计算叉积的向量的输入顺序的左手规则。食指和拇指彼此呈直角伸展,而中指在第三个平面上与食指成直角伸展。食指和拇指分别代表叉积计算的第一和第二输入向量。中指表示生成的法线。

“左手法则”可用于决定将两个向量传递给叉积函数的顺序。当您低头看表面的顶部(法线将从那里指向外)时,第一个向量应该顺时针扫到第二个向量:

如果输入向量的顺序相反,结果将指向完全相反的方向。

对于网格,法向量也必须归一化。这可以通过归一化属性来完成,但还有另一个偶尔有用的技巧。您还可以通过将垂直向量除以其大小来归一化它:-

float perpLength = perp.magnitude;
perp /= perpLength;

另一个有用的注意事项是三角形的面积等于perpLength/ 2. 如果您需要找到整个网格的表面积,或者想要根据三角形的相对面积随机选择三角形,这非常有用。

其他资源

数学编程
使用常用数学函数