文章目录
LearnGL - 学习笔记目录
本人才疏学浅,如有什么错误,望不吝指出。
上一篇:LearnGL - 05.3 - 封装 Main.cpp 中重复 GLFW代码,让新建的项目更方便的开展。
这一篇:这篇我们在讲一丢丢关于矩阵的内容。
本来我不想写关于矩阵的内容。因为要排版很多内容(LaTex挺多),-_-!!!,但是想了一下,还是加上吧,因为这个是我自己以前看过的资料总结的,先暂时写这么多,后续有空再补上关于矩阵的其他内容。
这里推荐一下关于矩阵的完整系统教学,我也是参考了其他网站上关于 OpenGL 学习资料中的:变换,这篇文章里介绍的:
可汗学院
- 可汗学院-线性代数-矩阵-在线视频、习题、小考 - (什么时候国内的在线免费教育能做到这样,教育方面就进步了)
- 矩阵变换
最近需要系统学习一下这方面资料,发现他这在线免费的教程资料太太太好了,忍不住要分享一下。
相比我之前在:网易公开课,里看的熟肉的质量好多了,因为我上面推荐的可汗学院的网站是官方网,虽然的内容是英文版,但是还好的是陌生单词不会很多。
可汗的故事以前看过,反正后来是比尔盖茨投资他继续为科学教育助力,因为比尔盖茨也是他的粉丝,而我,是比尔盖茨的粉丝。

看看:“A world class education for anyone, anywhere 100% free。”,这就是初心,感动人的工匠,这是造福人类啊。
OK,那么开始正文:
变换 这篇文章里排版什么的我是非常喜欢,看起来很舒服。
但里面刚好有一丢丢我会的内容没提到,我也在此基础上添加一丢丢笔记吧。
注意,什么是 向量、标量向量相乘、向量加减法、向量点积、向量乘积、矩阵乘法 我都不再说明,因为 变换 说得足够的清晰了。
点在坐标系下的定位
我们先了解 点在坐标系下的定位
先看看坐标轴长什么样:

这些内容大家肯定了解,毕竟都是初中知识。
O是坐标系原点,X就是X轴,其他两个就是Y轴和Z轴。
它们看起来就像是 三个向量。
没错,就是三个向量,OK,那么我们将它们每个轴的向量都标记上向量分量:

我们先给轴都定义一个标识符(字母上面加一个指向右的箭头)吧: X → \overrightarrow X X 表 X轴,以此类推 Y → 、 Z → \overrightarrow Y、\overrightarrow Z Y、Z。
然后原点是: O O O
X → = ( 1 , 0 , 0 ) \overrightarrow X=(1,0,0) X=(1,0,0)
Y → = ( 0 , 1 , 0 ) \overrightarrow Y=(0,1,0) Y=(0,1,0)
Z → = ( 0 , 0 , 1 ) \overrightarrow Z=(0,0,1) Z=(0,0,1)
从坐标轴长度可以看出来,都是 1的长度(单位化向量长度都是1)。
所以三个向量都是 单位向量(基向量)。
而且三个向量都是相互 垂直的(正交的)。
所以我们也可以叫:正交基向量,也叫 自然基、标准化(归一化)基向量,叫法挺多,选一个方便我们理解的就好,暂时选用 正交基向量。
如果我有任意一个点像在此坐标系下显示位置,我们如果处理呢?
假设我有一个点P,它就在原点O(0,0,0)的位置上,它和原点重合了,我们想让它右边(X轴正方向)移动0.5的位移量,好让我们看清这个点:
那么下面P点的位置变成了: O + 0.5 X → O+0.5 \overrightarrow X O+0.5X
就是在:原点 O O O基础上往 X → \overrightarrow X X偏移0.5的量
O = ( 0 , 0 , 0 ) , X → = ( 1 , 0 , 0 ) O=(0,0,0), \overrightarrow X=(1,0,0) O=(0,0,0),X=(1,0,0)
P 点 = O + 0.5 X → P点=O+0.5\overrightarrow X P点=O+0.5X
= ( 0 , 0 , 0 ) + 0.5 ⋅ ( 1 , 0 , 0 ) =(0,0,0)+0.5\cdot(1,0,0) =(0,0,0)+0.5⋅(1,0,0)
= ( 0.5 , 0 , 0 ) =(0.5,0,0) =(0.5,0,0)

然后再向上(Y轴正方向)移动0.2个位移量: O + 0.5 X → + 0.2 Y → O+0.5\overrightarrow X+0.2\overrightarrow Y O+0.5X+0.2Y
就是在:原点 O O O基础上往 X → \overrightarrow X X偏移0.5的量,再往 Y → \overrightarrow Y Y偏移0.2的量
O = ( 0 , 0 , 0 ) , X → = ( 1 , 0 , 0 ) , Y → = ( 0 , 1 , 0 ) O=(0,0,0), \overrightarrow X=(1,0,0),\overrightarrow Y=(0,1,0) O=(0,0,0),X=(1,0,0),Y=(0,1,0)
P 点 = O + 0.5 X → + 0.2 Y → P点=O+0.5\overrightarrow X+0.2\overrightarrow Y P点=O+0.5X+0.2Y
= ( 0 , 0 , 0 ) + 0.5 ⋅ ( 1 , 0 , 0 ) + 0.2 ⋅ ( 0 , 1 , 0 ) =(0,0,0)+0.5\cdot(1,0,0)+0.2\cdot(0,1,0) =(0,0,0)+0.5⋅(1,0,0)+0.2⋅(0,1,0)
= ( 0.5 , 0 , 0 ) + ( 0 , 0.2 , 0 ) =(0.5,0,0)+(0,0.2,0) =(0.5,0,0)+(0,0.2,0)
= ( 0.5 , 0.2 , 0 ) =(0.5,0.2,0) =(0.5,0.2,0)

然后再向前(Z轴正方向)移动0.5个位移量: O + 0.5 X → + 0.2 Y → + 0.5 Z → O+0.5\overrightarrow X+0.2\overrightarrow Y+0.5\overrightarrow Z O+0.5X+0.2Y+0.5Z
就是在:原点 O O O基础上往 X → \overrightarrow X X偏移0.5的量,再往 Y → \overrightarrow Y Y偏移0.2的量,再往 Z → \overrightarrow Z Z偏移0.5的量
O = ( 0 , 0 , 0 ) , X → = ( 1 , 0 , 0 ) , Y → = ( 0 , 1 , 0 ) , Z → = ( 0 , 0 , 1 ) O=(0,0,0), \overrightarrow X=(1,0,0),\overrightarrow Y=(0,1,0),\overrightarrow Z=(0,0,1) O=(0,0,0),X=(1,0,0),Y=(0,1,0),Z=(0,0,1)
P 点 = O + 0.5 X → + 0.2 Y → + 0.5 Z → P点=O+0.5\overrightarrow X+0.2\overrightarrow Y+0.5\overrightarrow Z P点=O+0.5X+0.2Y+0.5Z
= ( 0 , 0 , 0 ) + 0.5 ⋅ ( 1 , 0 , 0 ) + 0.2 ⋅ ( 0 , 1 , 0 ) + 0.5 ⋅ ( 0 , 0 , 1 ) =(0,0,0)+0.5\cdot(1,0,0)+0.2\cdot(0,1,0)+0.5\cdot(0,0,1) =(0,0,0)+0.5⋅(1,0,0)+0.2⋅(0,1,0)+0.5⋅(0,0,1)
= ( 0.5 , 0 , 0 ) + ( 0 , 0.2 , 0 ) + ( 0 , 0 , 0.5 ) =(0.5,0,0)+(0,0.2,0)+(0,0,0.5) =(0.5,0,0)+(0,0.2,0)+(0,0,0.5)
= ( 0.5 , 0.2 , 0.5 ) =(0.5,0.2,0.5) =(0.5,0.2,0.5)

OK,这就是点 P ( 0.5 , 0.2 , 0.5 ) P(0.5,0.2,0.5) P(0.5,0.2,0.5)在此坐标系下的位置。
更重要的是,我们得出了一个式子: O + 0.5 X → + 0.2 Y → + 0.5 Z → O+0.5\overrightarrow X+0.2\overrightarrow Y+0.5\overrightarrow Z O+0.5X+0.2Y+0.5Z
再把: P ( 0.5 , 0.2 , 0.5 ) P(0.5,0.2,0.5) P(0.5,0.2,0.5),换成: P ( p x , p y , p z ) P(p_x,p_y,p_z) P(px,py,pz)
那么式子: O + 0.5 X → + 0.2 Y → + 0.5 Z → O+0.5\overrightarrow X+0.2\overrightarrow Y+0.5\overrightarrow Z O+0.5X+0.2Y+0.5Z
变成了: O + p x ⋅ X → + p y ⋅ Y → + p z ⋅ Z → O+p_x\cdot \overrightarrow X+p_y\cdot \overrightarrow Y+p_z\cdot \overrightarrow Z O+px⋅X+py⋅Y+pz⋅Z
其实这式子就是3D图形学中4x4矩阵的前身,因为这个式子可以表示一次变换。
注意:而使用矩阵的原因是因为矩阵数据集合本身可以修改。假设我们有一个矩阵变换(坐标系)A,只要我们用另一个矩阵变换 B 去修改它,那么它就相当于在原来的矩阵的变换(或是说坐标系)基础上,再次改变了坐标系的轴(旋转或缩放),变成了另一个新的坐标系:C, C = B ⋅ A C = B\cdot A C=B⋅A,这个 C 矩阵就相当于柔和了 A 和 B 矩阵变换的累积变换。
我就举个机械手臂的例子:

将他们的每个子矩阵变换,或者说是子坐标系,罗列一下可以有这么几个

有:
- A A A 它是我们的肱二头肌
- B B B 是手腕
- C C C 是类似人类手掌
- D 1 , D 2 D_1,D_2 D1,D2 是手指 D D D关节1、2
- E 1 , E 2 E_1,E_2 E1,E2 是手指 E E E关节1、2
- F 1 , F 2 F_1,F_2 F1,F2 是手指 F F F关节1、2
- G G G 是我们的红球
其中 G 会比较特殊
从 A A A到 G G G都的坐标系之前的嵌套可以理解为:
A
|
+--->B
|
+--->C
|
+--->D_1
| |
| +--->D2
+--->E_1
| |
| +--->E_2
+--->F_1
|
+--->F_2
G 呢?它没有属于机械手臂的坐标系吗?因为我们的机械手臂的D,E,F关节都是可以旋转而夹紧红球 G,并且 D,E,F 不再变换后,D,E,F,G都数据 C 的子坐标系。
只要 G 求没有东西固定它,它都属于世界坐标。
当然,我们上面通常是简单的游戏中的制作方法,更好的方法是直接使用物理系统来给球体、机械手臂添加物理刚体网格,让他们使用物理系统来驱动相应。
每一个关节都有一个坐标系,或是说:矩阵变换。
如果我们驱动 A 矩阵变换,那么其他所有的 子坐标 或是说 子矩阵变换 都一同跟着变换,如果我们驱动 B,那么 A 保持不动,B 下的所有 子矩阵变换 又会跟着变化。(有些系统是例外,如:实现IK动力学,是需要 子矩阵变换 来计算驱动 父级矩阵 如何变化的)
这些每个坐标系相对世界坐标系统( I , 单 位 矩 阵 , 对 角 都 是 1 , 其 余 都 为 0 I,单位矩阵,对角都是1,其余都为0 I,单位矩阵,对角都是1,其余都为0)来说,他们都可以这么表示:
- I ⋅ A I\cdot A I⋅A
- I ⋅ A ⋅ B I\cdot A \cdot B I⋅A⋅B
- I ⋅ A ⋅ B ⋅ C I\cdot A \cdot B \cdot C I⋅A⋅B⋅C
- I ⋅ A ⋅ B ⋅ C ⋅ D 1 I\cdot A \cdot B \cdot C \cdot D_1 I⋅A⋅B⋅C⋅D1
- I ⋅ A ⋅ B ⋅ C ⋅ D 1 ⋅ D 2 I\cdot A \cdot B \cdot C \cdot D_1 \cdot D_2 I⋅A⋅B⋅C⋅D1⋅D2
- I ⋅ A ⋅ B ⋅ C ⋅ E 1 I\cdot A \cdot B \cdot C \cdot E_1 I⋅A⋅B⋅C⋅E1
- I ⋅ A ⋅ B ⋅ C ⋅ E 1 ⋅ E 2 I\cdot A \cdot B \cdot C \cdot E_1 \cdot E_2 I⋅A⋅B⋅C⋅E1⋅E2
- I ⋅ A ⋅ B ⋅ C ⋅ F 1 I\cdot A \cdot B \cdot C \cdot F_1 I⋅A⋅B⋅C⋅F1
- I ⋅ A ⋅ B ⋅ C ⋅ F 1 ⋅ F 2 I\cdot A \cdot B \cdot C \cdot F_1 \cdot F_2 I⋅A⋅B⋅C⋅F1⋅F2
继续上面的 坐标系下点的定位的 内容,我们可以将: O + p x ⋅ X → + p y ⋅ Y → + p z ⋅ Z → O+p_x\cdot \overrightarrow X+p_y\cdot \overrightarrow Y+p_z\cdot \overrightarrow Z O+px⋅X+py⋅Y+pz⋅Z写成矩阵的方式:
首先是每个轴,我们都写成3x3中某个列的向量来表示:
X → = [ ∣ X → ∣ ] , Y → = [ ∣ Y → ∣ ] , Z → = [ ∣ Z → ∣ ] \overrightarrow X=\begin{bmatrix}|\\\overrightarrow X\\|\end{bmatrix},\overrightarrow Y=\begin{bmatrix}|\\\overrightarrow Y\\|\end{bmatrix},\overrightarrow Z=\begin{bmatrix}|\\\overrightarrow Z\\|\end{bmatrix} X=⎣⎡∣X∣⎦⎤,Y=⎣⎡∣Y∣⎦⎤,Z=⎣⎡∣Z∣⎦⎤
这样我们的三个 正交基向量 就构成了一个3x3矩阵: M M M
M = [ ∣ ∣ ∣ X → Y → Z → ∣ ∣ ∣ ] M=\begin{bmatrix} | & | & |\\ \overrightarrow X & \overrightarrow Y & \overrightarrow Z\\ | & | & | \end{bmatrix} M=⎣⎡∣X∣∣Y∣∣Z∣⎦⎤
然后是我们的点 P P P可以是表示为一个3x1的向量(矩阵):
( p x p y p z ) \left(\begin{matrix} p_x\\ p_y\\ p_z\end{matrix}\right) ⎝⎛pxpypz⎠⎞
然后是点 P P P在 M M M坐标系(变换矩阵)中定位后(变换后)的坐标定义为: P 1 P1 P1,那么 P 1 P1 P1等于:
( p 1 x p 1 y p 1 z ) \left(\begin{matrix} p1_x\\ p1_y\\ p1_z\end{matrix}\right) ⎝⎛p1xp1yp1z⎠⎞
P 1 = M ⋅ P → ( p 1 x p 1 y p 1 z ) = [ ∣ ∣ ∣ X → Y → Z → ∣ ∣ ∣ ] ⋅ ( p x p y p z ) → p x ⋅ X → + p y ⋅ Y → + p z ⋅ Z → P1=M\cdot P \rightarrow \left(\begin{matrix} p1_x\\ p1_y\\ p1_z\end{matrix}\right) =\begin{bmatrix} | & | & |\\ \overrightarrow X & \overrightarrow Y & \overrightarrow Z\\ | & | & | \end{bmatrix} \cdot \left(\begin{matrix} p_x\\ p_y\\ p_z\end{matrix}\right) \rightarrow p_x\cdot \overrightarrow X+p_y\cdot \overrightarrow Y+p_z\cdot \overrightarrow Z P1=M⋅P→⎝⎛p1xp1yp1z⎠⎞=⎣⎡∣X∣∣Y∣∣Z

本文深入探讨3D图形学中的矩阵变换,包括点在坐标系下的定位、矩阵的扩展与偏移、齐次坐标的概念及应用、缩放与旋转矩阵的理解。通过实例解析,阐述了矩阵在3D空间中如何实现坐标变换、缩放和旋转,以及如何避免万向锁问题。
&spm=1001.2101.3001.5002&articleId=106819425&d=1&t=3&u=040e5a254fc744788a39769c51d3a529)
4180

被折叠的 条评论
为什么被折叠?



