一文读懂 THREE.JS 中的向量

您所在的位置:网站首页 向量夹角的余弦值公式怎么求 一文读懂 THREE.JS 中的向量

一文读懂 THREE.JS 中的向量

2023-06-05 09:47| 来源: 网络整理| 查看: 265

在 three.js 中,向量是最基础的元素,无论是单纯表示方向的向量还是法向量,其本质都是为了表示物体的位置、运动的方向或者是面的朝向以及各种和方向或角度相关的计算,所以只要我们使用 three.js,在有意或者无意中都一定会用到向量,正确的使用向量,往往会给我们的计算带来意想不到的便利。

1、向量的概述

向量在数学中表示一种既有大小又有方向的量,又称为矢量。在 three.js 中向量主要可以表示为

(1)一个位于二(三|四)维空间中的点; (2)一个在二(三|四)维空间中的方向与长度的定义; (3)任意的、有顺序的、二(三|四)个为一组的数字组合。

three.js 中的向量既可以表示空间中的一个点位,又可以表示从坐标原点到该点的一个向量,至于在什么情况下理解为点位,什么情况下理解为向量,可以根据需要来定义,那么在下文中我们也会举例来讲。

2、向量的属性

我们访问向量再每个方向上的值的(x、y、z、w)可以直接通过向量的 x、y、z、属性访问,其中二维向量不仅有 x、y 属性,还有 width(值等同于 x)和 height(值等同于 y)属性,而四维向量也有这两个属性,只是 width 的值等同于 z 而 height 的值等同于 w,此外二(三|四)维向量均有一个检测方法 isVector2(3|4),该方法为只读属性用于检查给定对象的类型是否为 Vector2(3|4)。

3、向量的方法

向量方法有很多,这里只列出二(三、四)维向量的一些共有方法的含义,并重点解析几个方法的由来。

.add ( v : Vector2(3|4) ) : 将传入的向量 v 和这个向量相加。 .addScalar ( s : Float ) : 将传入的标量 s 和这个向量的 x 值、y 值(z 值、w 值)相加。 .addScaledVector ( v : Vector2(3|4), s : Float ) : 将所传入的 v 与 s 相乘所得乘积和这个向量相加。 .addVectors ( a : Vector2(3|4), b : Vector2(3|4) ) : 将该向量设置为 a + b。 .ceil () : 向量中的 x 分量和 y 分量向上取整为最接近的整数值。 .clone () : Vector2(3|4) 返回一个新的 Vector2(3|4),其具有和当前这个向量相同的 x 和 y。 .copy ( v : Vector2(3|4) ) : 将所传入 Vector2(3|4) 的 x 和 y 属性复制给这一 Vector2(3|4)。 .dot ( v : Vector2 ) : 计算该 vector 和所传入 v 的点积(dot product)。 .cross ( v : Vector2 ) : 计算该 vector 和所传入 v 的叉积(cross product),请注意,“叉积”在 2D 中并没有被明确定义,该函数计算的是 2D 图形中经常使用的几何叉积,且四维向量没有该方法。 .equals ( v : Vector2(3|4) ) : 检查该向量和 v 的严格相等性。 .floor () : 向量的分量向下取整为最接近的整数值。 .length () : 计算从(0, 0, 0, 0)到(x, y, z, w)的直线长度,二维和三维同理。 .set ( x : Float, y : Float, z : Float, w : Float ) : 设置该向量的 x、y 、z、w 方向的分量。 .setLength ( l : Float ) : 将该向量的方向设置为和原向量相同,但是长度(length)为 l。 .setScalar ( scalar : Float ) : 将该向量的 x、y(z、w) 值同时设置为等于传入的 scalar。 .setX ( x : Float ) : 将向量中的 x 值替换为 x。 .setY ( y : Float ) : 将向量中的 y 值替换为 y。 .setZ ( z : Float ) : 将向量中的 z 值替换为 z。(三|四维向量有此方法) .setW ( w : Float ) : 将向量中的 w 值替换为 w。仅四维向量有此方法 .sub ( v : Vector2(3|4) ) : 从该向量减去向量 v。 .subScalar ( s : Float ) : 从该向量的 x、y、z、w 中减去标量 s。 .subVectors ( a : Vector2(3|4), b : Vector2(3|4) ) : 将该向量设置为 a - b。 .normalize () : 将该向量转换为单位向量(unit vector), 也就是说,将该向量的方向设置为和原向量相同,但是其长度(length)为 1,即归一化。 .toArray ( array : Array, offset : Integer ) : 返回一个数组[x, y, z, w],或者将 x、y、z 和 w 复制到所传入的 array 中。 .random () : 将该向量的每个分量(x、y、z、w)设置为介于 0 和 1 之间的伪随机数,不包括 1。

下面举例说明三维向量 Vector3 的.sub、.dot、.cross 这几个方法的几个运用场景,以及在数学上的推理过程,仅个人观点。

(1)知道两个点的位置,求两点组成的线段的方向向量

已知 A 为坐标原点,B、C 为三维空间中的两个点,求这两个点位组成的线段 BC 的方向向量。

我们可以先确定方向,例如求 B 点到 C 点的方向向量,可以先将 BC 线段的两个端点 B、C 点都减去 B 点值,得到B1B_1B1​、C1C_1C1​点,其中B1B_1B1​点坐标与坐标原点重合,C1C_1C1​点位置即为 C 点坐标减去 B 点坐标所得值,得到与 BC 线段平行的线段B1C1B_1C_1B1​C1​,而B1C1B_1C_1B1​C1​的方向向量即是 BC 的方向向量,具体公式如下:

const A = Vector3(0, 0, 0); const B = Vector3(1, 2, 0); const C = Vector3(-2, 1, 2); const bc = C.clone().sub(B); // Vector3(-3, -1, 2) *注.sub方法会改变执行它的向量的值,使用之前需先克隆该向量

以上向量 bc 便是 B 点到 C 点的方向向量,同理可得 C 点到 B 点的方向即为 bc 的反向量,即 bc.negate()

(2)知道线段的方向、长度以及其中一个端点,求另一个端点

由上(1)我们可以反推,首先方向向量确定,且长度确定(若为标准向量可自行设置长度),可以得到与 BC 向量方向相同、长度相等并且以坐标原点为其中一个端点的线段B1C1B_1C_1B1​C1​,若已知 B 点坐标求 C 点坐标,则用 B 点坐标与方向向量 BC 相加,若已知 C 点坐标求 B 点坐标,则是 C 点坐标与方向向量相减,如下:

// 已知B点坐标求C点坐标 const bc = Vector3(-3, -1, 2); // 方向向量 const B = Vector3(1, 2, 0); // 确定的端点 const C = B.clone().add(bc); // Vector3(-2, 1, 2) // 已知C点坐标求B点坐标 const bc = Vector3(-3, -1, 2); // 方向向量 const C = Vector3(-2, 1, 2); // 确定的端点 const B = C.clone().sub(bc); // Vector3(1, 2, 0) (3)通过点积(dot)判断向量之间的夹角

以(1)中向量 B 与向量 C 为例计算,则向量 B 与向量 C 夹角的余弦值为 B.clone().normalize().dot(C.normalize())。证明如下: 根据余弦定理,三角形任一边的平方等于其他两边平方和减去这两边与他们夹角的余弦的积的两倍。若 a、b、c 分别表示Δ\DeltaΔABC 中 A、B、C 的对边,则余弦定理可表述为:

a2=b2+c2−2bca^2 = b^2 + c^2 - 2bca2=b2+c2−2bc cosAcosAcosA, b2=a2+c2−2acb^2 = a^2 + c^2 - 2acb2=a2+c2−2ac cosBcosBcosB, c2=a2+b2−2abc^2 = a^2 + b^2 - 2abc2=a2+b2−2ab cosCcosCcosC。

余弦定理还可以用以下形式表达:

cosAcosAcosA = (b2+c2−a2)2bc(b^2 + c^2 - a^2)\over2bc2bc(b2+c2−a2)​

cosBcosBcosB = (a2+c2−b2)2ac(a^2 + c^2 - b^2)\over2ac2ac(a2+c2−b2)​

cosCcosCcosC = (a2+b2−c2)2ab(a^2 + b^2 - c^2)\over2ab2ab(a2+b2−c2)​

下面我们开始进行推算,首先定义三个点位 A、B、C

const A = Vector3(0, 0, 0); // 坐标原点 const B = Vector3(x1, y1, z1); const C = Vector3(x2, y2, z2);

我们假设 A、B、C 都是被归一化后的标准向量且 AB=c=1,AC=b=1,BC=a,那么根据上图公式可以得出: cos A = (x12+y12+z12+x22+y22+z22x_1^2 + y_1^2 + z_1^2 + x_2^2 + y_2^2 + z_2^2x12​+y12​+z12​+x22​+y22​+z22​ - ((x1−x2)2+(y1−y2)2+(z1−z2)2(x_1-x_2)^2 + (y_1-y_2)^2 + (z_1-z_2)^2(x1​−x2​)2+(y1​−y2​)2+(z1​−z2​)2) / 2bc = (2x1x2+2y1y2+2z1z2)(2x_1x_2 + 2y_1y_2 + 2z_1z_2)(2x1​x2​+2y1​y2​+2z1​z2​) / 2 = x1x2+y1y2+z1z2x_1x_2 + y_1y_2 + z_1z_2x1​x2​+y1​y2​+z1​z2​ 而 B.dot(C)得到的也是x1x2+y1y2+z1z2x_1x_2 + y_1y_2 + z_1z_2x1​x2​+y1​y2​+z1​z2​的值,故此,两个标准向量的点积求出的即是两个向量夹角的余弦值

(4)叉乘(cross)两个向量的叉乘所得向量与这两个向量同时垂直 // 假设向量G是由向量E、F叉乘所得 const E = Vector3(0, 1, 5); const F = Vector3(1, 0, 5); const G = E.clone().cross(F); // Vector3(5, 5, -1) console.log(E.clone().dot(G)); // 0 console.log(F.clone().dot(G)); // 0

由于我们已经知道两个向量的点积的值即是这两个向量的余弦值,而垂直角的余弦值为 0,由此可知向量 G 与向量 E、F 的夹角都为垂直角,可以得出 E、F 点与坐标原点所构成平面的法向量就是向量 G,这一点于实际开发中也会很有用。

总结

当然,向量的方法还有很多,笔者就不再做一一解释,由于官方文档对这些方法的解释较为简洁,对于初学者来说,理解起来有一定难度,希望更多的小伙伴能写下自己的理解和感悟,大家一起学习,共同进步!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3