likes
comments
collection
share

高级前端应该掌握的数学知识-矢量

作者站长头像
站长
· 阅读数 30

随着前端技术的发展,与前端相关的知识也越来越多,这么多知识要想全部掌握就需要大量的时间,当然要全部掌握也是不太现实的。所以我们需要在其中选择合适的知识进行深入学习。

那么前端应该需要掌握什么知识呢?大家平时最多的工作相信还是切图,实现 UI 给的设计图,无论是使用 Vue 还是 React,切图切多了也觉得没啥意思,因为只是使用的话,它们都比较简单,没啥技术难度,平时开发也无法深入到 Vue 和 React 源码。

熟悉使用 Vue 和 React 开发后,自己技术水平将会很难再进行提升,好像遇到了瓶颈,技术水平也一直原地踏步。为了突破瓶颈,这时候大家可能会没有计划的一通乱学前端知识,比如各个框架,类库的使用又或者是 node.js 后端开发。快速学习后好像自己什么都会了,是全栈工程师了,但是一面试又是一问三不知,因为自己都只是学的皮毛,只能勉强简单的做一些玩具类的东西出来,但是实际工作中是需要对这个领域非常深入的知识。

所以我们需要真正的深入一个领域,而不会乱学一通,好像都会了,好像什么都不会,什么都只是入门水平,离领域高级开发还差的远。

说到前端要深入的知识,那么必不可少就是图形可视化领域了。我们都知道前端和 UI 走的近,前端负责开发图形界面,所以本质上前端的工作是图形和可视化相关的。

很多人说前端开发不涉及数学知识,但是要深入图形开发,那么图形可视化相关的数学知识和 WebGL 就是必须要掌握的技能,这也是高级前端需要了解的知识。

《零基础玩转 WebGL》 就是深入图形开发系列教程文章,其中包括 WebGL,图形学和图形相关的数学知识。深入的学习它会有一些难度,但这正是高级开发和初中级的分界线。如果想真正的变强的话,就需要学些有难度的东西,不然也不能和其他前端拉开差距。

接下来讲解《零基础玩转 WebGL》系列教程的第 3 篇文章,上一篇文章 零基础玩转 WebGL - 着色器,当然这篇文章比较独立没和之前的文章没有太多的关联性。

这篇文章讲解 WebGL 图形学可视化开发中必须掌握的数学知识 - 矢量。下面的纯数学知识可能没那么好理解,大家可以先对矢量有个大致的了解。在后续开发的实战文章中遇到相关知识,可以再回过头来了解这些基础知识。

矢量是什么?

矢量(Vector)也称为向量是数学、物理学和工程科学等多个自然科学中的基本概念。矢量同时具有大小和方向,需要注意的是矢量是没有固定位置的,它可以在空间中随便移动。

在实际编码中,矢量其实就是一个普通的数组,如 [X,Y,Z][X, Y, Z][X,Y,Z] 。矢量在表示时,会在上方加一个箭头,如矢量 A→\overrightarrow{A}A ,下面为了简单就不加箭头了。

我们知道矢量只有方向和大小,没有位置。如下图所示,矢量 A 可以表示为 [1,1][1, 1][1,1] ,它和矢量 B 是同一个矢量,因为矢量没有位置,所以可以随便的移动它,最终还是表示同一个矢量。矢量带箭头的那一端称为终点,另一端称为起点。

高级前端应该掌握的数学知识-矢量

零矢量

有个特殊的矢量零矢量,零矢量每个位置都是 0 ,如三维零矢量可以表示为 [0,0,0][0, 0, 0][0,0,0],零矢量没有大小、没有方向当然它也没有位置。任何矢量加上零矢量都等于它本身。

矢量加减法

矢量的加减法就和标量的加减法一样,就是把矢量的对应项加或减起来。矢量只能和同维度的矢量相加或相减。也就是 2D 矢量只能和 2D 矢量进行运算,不能和 3D 矢量运算。具体操作,如下所示。

[x1, y1, z1] + [x2, y2, z2] = [x1 + x2, y1 + y2, z1 + z2]

[x1, y1, z1] - [x2, y2, z2] = [x1 - x2, y1 - y2, z1 - z2]

矢量加法是可交换的 A+B=B+AA + B = B + AA+B=B+A,矢量减法可反交换 A−B=−(B−A)A - B = -(B - A)AB=(BA),就和标量一样。

在几何空间中,矢量的加减法对应的可视化,如下图所示。

高级前端应该掌握的数学知识-矢量

A+BA + BA+B 是把一个点先应用 A ,然后应用 B ,然后 A+BA + BA+B 就等于从 A 的尾部到 B 的头部的矢量。 A−BA - BAB 也是一样,先应用 A,再应用 -B (也就是将 B 的方向反转下)。需要注意的是 A−BA - BABB−AB - ABA 是两个方向相反的矢量。

标量和矢量乘法

标量和矢量乘法也非常简单,直接用标量乘上矢量中各个项就行了。

k * [x, y, z] = [kx, ky, kz]

如果 k-1 时,会得到矢量的负矢量(方向相反,大小相等)。

在几何中,标量乘矢量,标量就是矢量长度的缩放因子,如 k 等于 2,那么所得矢量是原矢量两倍长。

矢量大小

矢量的大小用双垂直线表示,比如矢量 AAA 的大小表示为 ∥A∥\| A \|A 。要计算矢量大小也非常简单,直接对它进行勾股定理运算就行了,计算方式如下所示。

∥A∥=∥[x,y]∥=x2+y2\| A \| = \| [x, y] \| = \sqrt{x^2+y^2}A=[x,y]=x2+y2
∥B∥=∥[x,y,z]∥=x2+y2+z2\| B \| = \| [x, y, z] \| = \sqrt{x^2+y^2+z^2}B=[x,y,z]=x2+y2+z2

高级前端应该掌握的数学知识-矢量

如上图所示,计算矢量的大小其实就是计算直角三角形斜边的大小,我们知道直角三角形两条直角边的大小,那么直接使用勾股定理就可以计算出矢量的大小。

单位矢量

另一个特殊的矢量是单位矢量,单位矢量是大小为 1 的矢量,单位矢量也称为归一化矢量或法线,称为法线时一般表示该矢量垂直于一个表面。(后续文章将详细讲解有意思的法线)

要归一化一个矢量,只需要将矢量除以它的大小就行了,计算方式如下所示。

len=∥[x,y,z]∥=x2+y2+z2len = \| [x,y,z] \| = \sqrt{x^2+y^2+z^2}len=[x,y,z]=x2+y2+z2
norm=[x,y,z]len=[xlen,ylen,zlen]norm = \frac{[x, y, z]}{len} = [\frac{x}{len}, \frac{y}{len}, \frac{z}{len}]norm=len[x,y,z]=[lenx,leny,lenz]

归一化一个矢量,就是将矢量的长度变为 1,方向不变。

矢量乘法

矢量和矢量的乘法一共有两种方式,分别是点积和叉积。

点积

矢量点积的结果是一个标量,点积乘法的符号是一个点 ·,运算方式是将两个矢量各个分量相乘再相加。如下所示。

[x1,y1,z1]⋅[x2,y2,z2]=x1x2+y1y2+z1z2[x1,y1,z1] \cdot [x2,y2,z2] = x1x2 + y1y2 + z1z2[x1,y1,z1][x2,y2,z2]=x1x2+y1y2+z1z2

矢量点积运算满足如下性质。

A⋅B=B⋅AA \cdot B = B \cdot AAB=BA
(kA)⋅B=k(A⋅B)=A⋅(kB)(kA) \cdot B = k(A \cdot B) = A \cdot (kB)(kA)B=k(AB)=A(kB)
A⋅(B+C)=A⋅B+A⋅CA \cdot (B + C) = A \cdot B + A \cdot CA(B+C)=AB+AC
A⋅A=∥A∥2A \cdot A = \| A \|^2AA=A2

下面让我们看看在几何中,矢量点积的可视化效果。矢量点积在几何中可以解释为投影。下图中的矢量 A 为单位矢量。

高级前端应该掌握的数学知识-矢量

点积 A⋅BA \cdot BAB 等于 B 投影到平行于 A 的任意线上的有符号长度,乘以 A 的长度。

矢量的点积可以给两个矢量的方向做一个初略的判断,如果两个矢量方向差不多相同则点积大于 0,如果垂直则等于 0,如果差不多相反则小于 0

点积的另一个用处的是可以把一个矢量分解为两个矢量,分别是垂直分量和平行分量。

高级前端应该掌握的数学知识-矢量

上图中 A 还是单位矢量。我们知道 B 等于 B∥+B⊥B\| + B\botB+B。其中 ∥B∥∥\|B\shortparallel \|B 等于 A⋅BA \cdot BAB 。所以我们可以得出下面结论。

B∥=∥B∥∥∗A=(A⋅B)AB\| = \|B\shortparallel \| * A = (A \cdot B)AB=BA=(AB)A
B⊥=B−B∥=B−(A⋅B)AB\bot = B - B\| = B - (A \cdot B)AB=BB=B(AB)A

另外我们还可以利用点积求出两个矢量间的夹角。

高级前端应该掌握的数学知识-矢量

上图中 A 和 B 都是单位矢量。根据基本三角函数,cos(θ) 等于对边的邻边比斜边。

cos(θ)=A⋅B∥B∥=A⋅Bcos(\theta) = \frac{A \cdot B}{\| B \|} = A \cdot Bcos(θ)=BAB=AB

两个单位矢量的点积就等于它们之间的余旋值。那么我们也可以得出任何矢量之间余旋值得公式。

A⋅B=∥A∥∗∥B∥∗cos(θ)A \cdot B = \| A \| * \| B \| * cos(\theta)AB=ABcos(θ)
θ=arccos(A⋅B∥A∥∗∥B∥)\theta = arccos(\frac{A \cdot B}{\|A \| * \|B \|})θ=arccos(ABAB)

叉积

叉积只能应用在三维中,矢量叉积将产生三维矢量,矢量叉积使用 ×\times× 符号。两个矢量叉积公式如下。

[x1,y1,z1]×[x2,y2,z2]=[y1z2−z1y2,z1x2−x1z2,x1y2−y1x2][x1,y1,z1] \times [x2,y2,z2] = [y1z2 - z1y2, z1x2 - x1z2, x1y2 - y1x2][x1,y1,z1]×[x2,y2,z2]=[y1z2z1y2,z1x2x1z2,x1y2y1x2]

叉积和点积一起使用时,叉积优先 A⋅B×C=A⋅(B×C)A \cdot B \times C = A \cdot (B \times C)AB×C=A(B×C) ,因为如果点积优先的话,点积的结果是标量,不能再进行叉积运算。

矢量叉积运算还有如下特性。

A×B=−(B×A)A \times B = -(B \times A)A×B=(B×A)
(A×B)×C≠A×(B×C)(A \times B) \times C \not = A \times (B \times C)(A×B)×C=A×(B×C)

在几何上,叉积产生的矢量将垂直原始的两个矢量,并且 A×BA \times BA×B 的长度等于 A 的长度乘以 B 的长度乘以它们间的正弦值。如下图所示。

高级前端应该掌握的数学知识-矢量

∥A×B∥=∥A∥∗∥B∥∗sin(θ)\| A \times B \| = \| A \| * \| B \| * sin(\theta)A×B=ABsin(θ)

如果 A 和 B 平行,或如果 A 或 B 为零矢量,则 A×BA \times BA×B 的结果为零矢量。

A×BA \times BA×B 矢量会有两个方向,那么是哪个朝向的矢量呢?

我们需要将 B 矢量的尾部移动到 A 矢量的头部,然后观察是顺时针旋转还是逆时针旋转。

如果是顺时针旋转,在左手坐标系中 A×BA \times BA×B 会指向你,右手坐标系是远离。如果是逆时针旋转,在左手坐标系中 A×BA \times BA×B 是远离,右手坐标系是指向你。(如下图所示)

高级前端应该掌握的数学知识-矢量

其实我们也可以伸出双手,右手坐标系伸出右手,左手坐标系伸出左手。手握拳伸出大拇指,然后将 4 指按照上图旋转方向旋转,大拇指的方向就是 A×BA \times BA×B 的方向。(还记得在第一篇文章中讲解的 WebGL 是使用左手坐标系,坐标系和旋转方向将在后续文章中讲解)

矢量和点

看到这里大家脑中可能有一个疑问,矢量和点有啥区别,它们看起来都是一样的,例如 [x, y, z], 你可以说它是一个矢量,也可以说它是一个点。

但是需要注意的是矢量和点是两种概念,矢量有大小和方向,没有位置。而点只代表一个位置。

矢量可以描述位移,如果将 [2, 2] 的矢量,应用在 [1, 1] 的点上,则代表将点移动到 [3, 3] 位置。我们也可以将点表示为来自原点的矢量。

高级前端应该掌握的数学知识-矢量

如上图所示,矢量是一个箭头,而点就是指定位置上面的一个点,虽然它们都是使用 x, y 来表示。

另外还可以再添加一个分量来区分点和矢量,比如在三维中我们可以使用 4 个分量来区分点和矢量。[x, y, z, w],如果 w0 则代表矢量,否则代表是点,这也称为齐次坐标。(齐次坐标将在后续文章中讲解)

总结

这篇文章讲解了 WebGL 图形学可视化中必须要掌握的矢量知识,矢量是一个只有方向和大小,没有固定位置的箭头。和标量一样矢量也可以进行加减法和乘法操作,并且这些运算在几何中都有特定的可视化作用。这篇文章中介绍的公式可能比较难以一次性掌握,不过没有关系可以先知道有这个东西(给文章点个赞),以后碰到需要相关的知识时在来回顾。

学完了矢量我们还需要学习另一个非常重要的矩阵数学知识才能进行 WebGL 图形学应用开发,不然只能学会一些皮毛,没有深刻的理解内部的原理。如果觉得文章还不错欢迎点赞关注来支持鼓励作者,我会尽快更新系列教程的下一篇文章。

零基础玩转 WebGL 系列文章目录请查看:零基础玩转 WebGL - 目录