写在最前
往期回顾:
- # threejs系列: 相机与投影 📷
- # threejs系列: 光源与光照🪀
- # threejs系列: 自定义几何体🎃
- # threejs系列: 几何变换(上)🍺
- # threejs系列: 几何变换(下)🏄♂️
- threejs系列: 矩阵推导🎰
- threejs系列: 物体详解🐧
- threejs系列: 材质与贴图详解🦥
- threejs系列: 曲线详解🥓
- threejs系列: 动画详解🧠
- .......
高强度持续更新,从0到1深入了解 threejs 的奥秘,喜欢的点个关注呀
矩阵
数学上,矩阵定义为是一个有m行(row)n列(column)元素的矩形阵列。在线性代数中矩阵和向量是随处可见的,向量与矩阵的计算也是该熟记的。
下面是一个3 * 3的矩阵。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { 1 2 3 4 5 6 7 8 9 } \left\{ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{matrix} \right\} </math>⎩ ⎨ ⎧147258369⎭ ⎬ ⎫
矩阵加法
矩阵的加减法很简单,只需要把相对位置算数就可以,前提是矩阵的行列数相同。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { 1 4 } + { 2 5 } = { 1 + 2 4 + 5 } = { 3 9 } \left\{ \begin{matrix} 1\\ 4\\ \end{matrix} \right\} + \left\{ \begin{matrix} 2\\ 5\\ \end{matrix} \right\} = \left\{ \begin{matrix} 1 + 2\\ 4 + 5\\ \end{matrix} \right\} = \left\{ \begin{matrix} 3\\ 9\\ \end{matrix} \right\} </math>{14}+{25}={1+24+5}={39}
矩阵乘法
矩阵乘以一个数字:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { 1 4 } ∗ 4 = { 1 ∗ 4 4 ∗ 4 } = { 4 16 } \left\{ \begin{matrix} 1\\ 4\\ \end{matrix} \right\} * 4 = \left\{ \begin{matrix} 1 * 4\\ 4 * 4\\ \end{matrix} \right\} = \left\{ \begin{matrix} 4\\ 16\\ \end{matrix} \right\} </math>{14}∗4={1∗44∗4}={416}
矩阵与矩阵相乘:
前提:只有第一个矩阵的列的个数等于第二个矩阵的行的个数,这样的两个矩阵才能相乘。
A矩阵与B矩阵两个矩阵相乘得到的矩阵,会有矩阵A有相同的行数,会有矩阵B相同的列数。
例如:

2 * 3 矩阵 与 3 * 2 矩阵得到的就是一个 2 行 2 列的矩阵。
然后以分别进行 红蓝 、 红绿 、 橙蓝 、 橙绿组合进行点乘。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { a b c d f e } ∗ { h i j k l m } = { a ∗ h + b ∗ j + c ∗ l a ∗ i + b ∗ k + c ∗ m d ∗ h + f ∗ j + e ∗ l d ∗ i + f ∗ k + e ∗ m } \left\{ \begin{matrix} a & b & c\\ d & f & e\\ \end{matrix} \right\} * \left\{ \begin{matrix} h & i\\ j & k\\ l & m\\ \end{matrix} \right\} = \left\{ \begin{matrix} a * h + b * j + c* l & a * i + b * k + c * m\\ d * h + f * j + e * l & d * i + f * k + e * m\\ \end{matrix} \right\} </math>{adbfce}∗⎩ ⎨ ⎧hjlikm⎭ ⎬ ⎫={a∗h+b∗j+c∗ld∗h+f∗j+e∗la∗i+b∗k+c∗md∗i+f∗k+e∗m}
以上就是矩阵的简单计算。
向量
在上篇文章我们讲到的向量其实也能看作是一个m * 1的矩阵,比如:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 向量 [ x , y , z ] = { x y z } 向量 [x, y, z] = \left\{ \begin{matrix} x\\ y\\ z\\ \end{matrix} \right\} </math>向量[x,y,z]=⎩ ⎨ ⎧xyz⎭ ⎬ ⎫
在几何平面上:

<math xmlns="http://www.w3.org/1998/Math/MathML"> o j ⃗ 为 y 坐标的单位向量, o i ⃗ 为 x 坐标的单位向量, o A ⃗ 可以表示为 3 o i ⃗ + 2 o j ⃗ \vec{oj} 为y坐标的单位向量,\vec{oi}为x坐标的单位向量,\vec{oA}可以表示为 3\vec{oi} + 2\vec{oj} </math>oj 为y坐标的单位向量,oi 为x坐标的单位向量,oA 可以表示为3oi +2oj
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 则矩阵表示的话是为: 3 { 1 0 } + 2 { 0 1 } = { 3 ∗ 1 + 2 ∗ 0 3 ∗ 0 + 2 ∗ 1 } = { 3 2 } 则矩阵表示的话是为: 3 \left\{ \begin{matrix} 1\\ 0\\ \end{matrix} \right\} + 2 \left\{ \begin{matrix} 0\\ 1\\ \end{matrix} \right\} = \left\{ \begin{matrix} 3 * 1 + 2* 0\\ 3 * 0 + 2 * 1\\ \end{matrix} \right\} = \left\{ \begin{matrix} 3\\ 2\\ \end{matrix} \right\} </math>则矩阵表示的话是为:3{10}+2{01}={3∗1+2∗03∗0+2∗1}={32}
=
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 计算方式和矩阵如出一辙 { 1 0 0 1 } { 3 2 } = { 3 ∗ 1 + 2 ∗ 0 3 ∗ 0 + 2 ∗ 1 } = { 3 2 } 计算方式和矩阵如出一辙 \left\{ \begin{matrix} 1 & 0\\ 0 & 1\\ \end{matrix} \right\} \left\{ \begin{matrix} 3\\ 2\\ \end{matrix} \right\} = \left\{ \begin{matrix} 3 * 1 + 2* 0\\ 3 * 0 + 2 * 1\\ \end{matrix} \right\} = \left\{ \begin{matrix} 3\\ 2\\ \end{matrix} \right\} </math>计算方式和矩阵如出一辙{1001}{32}={3∗1+2∗03∗0+2∗1}={32}
这里由两个坐标系单位向量组成的矩阵也被称之为单位矩阵
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { 1 0 0 1 } \left\{ \begin{matrix} 1 & 0\\ 0 & 1\\ \end{matrix} \right\} </math>{1001}
图中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> o j ⃗ 和 o i ⃗ \vec{oj} 和 \vec{oi} </math>oj 和oi 也被称为坐标系的基向量
旋转矩阵推导
将坐标轴逆时针旋转45°
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> o i ⃗ 由旋转公式可得: { c o s 45 ° s i n 45 ° } , o j ⃗ = { − s i n 45 ° c o s 45 ° } \vec{oi}由旋转公式可得: \left\{ \begin{matrix} cos45°\\ sin45°\\ \end{matrix} \right\} , \vec{oj} = \left\{ \begin{matrix} -sin45°\\ cos45°\\ \end{matrix} \right\} </math>oi 由旋转公式可得:{cos45°sin45°},oj ={−sin45°cos45°}
矩阵表示为:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { c o s 45 ° − s i n 45 ° s i n 45 ° c o s 45 ° } { 3 2 } \left\{ \begin{matrix} cos45° & -sin45°\\ sin45° & cos45°\\ \end{matrix} \right\} \left\{ \begin{matrix} 3\\ 2\\ \end{matrix} \right\} </math>{cos45°sin45°−sin45°cos45°}{32}
所以平面旋转矩阵为:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { c o s 45 ° − s i n 45 ° s i n 45 ° c o s 45 ° } \left\{ \begin{matrix} cos45° & -sin45°\\ sin45° & cos45°\\ \end{matrix} \right\} </math>{cos45°sin45°−sin45°cos45°}
缩放矩阵推导
我们将坐标系缩小2倍
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> o i ⃗ 此时坐标: { 1 / z 0 } , o j ⃗ = { 0 1 / z } ,又因为 O A ⃗ = 3 O i ⃗ + 2 O j ⃗ ,所以矩阵表示为: { 1 / z 0 0 1 / z } { 3 2 } \vec{oi}此时坐标: \left\{ \begin{matrix} 1 / z\\ 0\\ \end{matrix} \right\} , \vec{oj} = \left\{ \begin{matrix} 0\\ 1 / z\\ \end{matrix} \right\} , 又因为\vec{OA} = 3\vec{Oi} + 2\vec{Oj}, 所以矩阵表示为: \left\{ \begin{matrix} 1 / z & 0\\ 0 & 1 / z\\ \end{matrix} \right\} \left\{ \begin{matrix} 3\\ 2\\ \end{matrix} \right\} </math>oi 此时坐标:{1/z0},oj ={01/z},又因为OA =3Oi +2Oj ,所以矩阵表示为:{1/z001/z}{32}
缩放矩阵为:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { z 0 0 z } \left\{ \begin{matrix} z & 0\\ 0 & z\\ \end{matrix} \right\} </math>{z00z}
线性变换
你会发现这种变换坐标系然后通过基向量获取点向量的方式很有趣,这种方式在数学中叫做线性变换
线性变换在几何直观上有如下特点:
- 变换前后,直线仍然保持是直线的状态
- 变换前后,原点保持固定,不会变化
平移矩阵推导
仿射变换
由于线性变换拥有原点固定的特点,所以无法进行平移,只能旋转和缩放。
一刻也无需为无法平移感伤,接下来出场的是 仿射变换
仿射变换与线性变换的最大不同就是原点可以移动。
通过添加一个维度进行线性变换然后在低纬度上投影,这样看上去就是在低纬度上移动了。

这张图形象的说明了仿射变换。
齐次坐标
齐次坐标就是将原先 n 维坐标改成 n + 1 维坐标表示。在3d图形学中,我们需要在向量中添加一个分量叫做 w ,表示在4维空间中的位置。物体的坐标其实是 (x/w, y/w ,z/w),因此当 w = 1 时,物体的xyz不会变化,所以通常我们都将 w 设置为1。
推导
我们回到平移推导,我们假设将坐标(x,y)平移到坐标(x',y'),因为线性变换无法平移,所以我们需乘以一个未知的齐次平移矩阵
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { x y z } ∗ { a b c d e f g h 1 } = { a x + b y + c z d x + e y + f z g x + h y + i z } \left\{ \begin{matrix} x\\ y\\ z\\ \end{matrix} \right\} * \left\{ \begin{matrix} a & b & c\\ d & e & f\\ g & h & 1\\ \end{matrix} \right\} = \left\{ \begin{matrix} ax + by + cz\\ dx + ey + fz\\ gx + hy + iz\\ \end{matrix} \right\} </math>⎩ ⎨ ⎧xyz⎭ ⎬ ⎫∗⎩ ⎨ ⎧adgbehcf1⎭ ⎬ ⎫=⎩ ⎨ ⎧ax+by+czdx+ey+fzgx+hy+iz⎭ ⎬ ⎫
得到以下等式
ini
x' = ax + by + cz;
y' = dx + ey + fz;
1 = gx + hy + z;
从式子我们可以首先得出 g = 0, h = 0, z = 1;
因为是平移,所以我们知道x'是 x移动了Tx, y'是y移动了Ty
ini
x' = x + Tx;
y' = y + Tx;
所以上面两个等式结合,我们可以知道,a = 1,b = 0, cz = Tx;d = 0, e = 1,f = Ty。
将其带入后得到平移矩阵
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { 1 0 T x 0 1 T y 0 0 1 } \left\{ \begin{matrix} 1 & 0 & Tx\\ 0 & 1 & Ty\\ 0 & 0 & 1\\ \end{matrix} \right\} </math>⎩ ⎨ ⎧100010TxTy1⎭ ⎬ ⎫
至此,三个基础得几何转换矩阵都得出来了,这里不禁感叹道还真是不容易呢😅
threejs 矩阵
矩阵的计算是相对复杂得,幸运的是threejs为我们封装了数学方法,接下来我们看看threejs如何使用矩阵。
threejs提供了Matrix4 类让我们快速的创建一个 4*4 矩阵。
m4 = new THREE.Matrix4();
然后通过.set方法进行填充元素。
m4.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
通过.element方法查看元素
m4.element

我们来进行矩阵进行几何变换:
js
// 缩放
mesh.matrix.makeScale(0.5, 0.5, 0.5);
mesh.matrixAutoUpdate = false;
API就不一一讲了,都是易懂的。