游戏中的数学:高等向量数学(上)

英文原文地址:Docs » Math » Advanced vector math

转载请注明出处

高等向量数学(advanced vector math)

平面(plane)

点乘和单位向量还有一个有趣的性质。试想一下,与某单位向量垂直且穿过原点的一个平面。该平面可以将整个空间划分为正向(平面以上)和负向(平面以下)两个部分,(与普遍看法相反)你也可以在2D中使用它们的数学公式:

image

垂直于面的单位向量(它们可以描述一个面的方向)被称为单位法向量(unit normal vector)。 尽管它们经常被简称为法线(normal)。法线会出现在平面以及3D几何(确定每个面或者顶点的朝向)等。法线是一个单位向量,但是由于它的用途,它被称为法线。(就像我们管(0,0)叫原点一样!)。

和看起来一样的简单。一个平面穿过原点并且它的面垂直于单位向量(或者叫法线)。在法向量方向一边的是正半空间,则另一边就是负半空间。在3D中也是完全一样的,只不过这时平面是一个无限的面(试想一个无限的平坦的纸,你可以控制它的朝向,并把它固定在原点)而不是一条线。

到平面的距离

现在我们已经清楚什么是平面了,那么再回到点乘的话题来。一个单位向量和空间中任意一点的点乘(是的,这次我们用向量和位置进行点乘),返回这个点到这个(法线所代表的)平面间的距离

var distance = normal.dot(point)

但不只是距离的绝对值(译者注:这个距离可正可负),如果这个点在负半空间,这个距离也是负的:

image

这使我们可以判断点在平面的哪一边。

远离原点

我知道你正在琢磨!到目前为止进展顺利,但是真正的平面会在空间的任何位置,而不一定要穿过原点。你想要看真正的平面并且马上就想看。

记住,平面不仅仅是把平面一分为二,它们是有极性的。这意味着可能会存在完美重合的平面,但它们的正负半空间是相反的。

带着这个概念,让我们用一个法线N和一个到原点的标量D来表示一个平面。因此我们的平面可以表示为ND,例如:

image

在3D中,Godot提供了一个Plane的内置类型可以处理这件事。

本质上,ND可以表示空间中的任何平面,无论是2D还是3D(这依赖于N的维度)并且数学公式也是相同的。和以前一样,只不过D是从原点沿着N方向到平面的距离。举个例子,如果你想到达平面上的一个点,你只要这样做:

var point_in_plane = N*D

这将伸展(改变大小)一个法向量让它碰到这个平面。这个数学公式看起来有点迷糊,但它实际上比看起来简单。如果你想再次获得这个点到这个平面的距离,我们也可以这样做只是稍微调整一下:

var distance = N.dot(point) - D

同样,我们也可以使用内置函数:

var distance = plane.distance_to(point)

再次提醒,这个函数的返回值可能是正的也可能是负的。

可以通过对ND同时取负来翻转一个平面极性。这样平面的位置不会变化,但是它的正负半空间会互换:

N = -N
D = -D

当然,Godot在Plane类中已经实现了这个运算符:

var inverted_plane = -plane

以上代码会如我们预期工作。

所以,请记住这就是平面,它的主要实际用途就是计算到它的距离。所以计算一个点到平面的距离非常有用?是的,它非常非常有用!让我们看一些简单的例子。

在2D中构造一个平面

译者注:这个部分是在2D中构造一个平面,也就是说所有平面都是和z轴平行的。

平面肯定不会凭空而出,它们必须被创建。在2D中创建平面非常简单,可以用一个法线和一个点,也可以用空间中的两个点.

如果用法线和点的话,大多数工作实际上已经完成了,因为法线已经计算好了,所以只需要用法线和点的点乘计算D就可以了。

var N = normal
var D = normal.dot(point)

对于空间中的两个点,实际上有两个平面穿过它们,这两个平面共享着空间但是法线的指向是相反的。要计算

两个点的法线必须先求出方向向量,然后旋转90°到另一个边:

# calculate vector from a to b
var dvec = (point_b - point_a).normalized()
# rotate 90 degrees
var normal = Vector2(dvec.y, -dvec.x)
# or alternatively
# var normal = Vector2(-dvec.y, dvec.x)
# depending the desired side of the normal

译者注: 向量(x,y)和(y,-x)以及(-y,x)都是垂直的

证明:(x,y)·(y,-x) = xy+y(-x)=xy-xy=0

剩下的步骤就和之前的例子相同了,用point_apoint_b都可以,因为它们在同一个平面上:

var N = normal
var D = normal.dot(point_a)
# this works the same
# var D = normal.dot(point_b)

在3D中是同理的,但是要稍复杂一些,我们会在稍后解释。

猜你喜欢

转载自blog.csdn.net/hello_tute/article/details/107835136