一文彻底弄懂三维变换矩阵

概述

三维变换矩阵是计算机图形学中处理三维空间几何变换的核心数学工具。它通过一个4x4的齐次坐标矩阵,统一表示几何体的平移、旋转和缩放。

本文先从数学角度对相关理论进行介绍,文章最后会从几何意义角度再次理解三维变换,让读者以更直观的方式将三维变换矩阵彻底搞懂

Alternative Text

三维变换矩阵的组成

在各种图形软件中,三维变换一般由平移、旋转和缩放三个变换组成。我们常见的镜像,可以当做变换系数为负的缩放来处理。

一般情况下,平移、旋转和镜像的组合顺序是先镜像,再旋转,最后平移。这个顺序不用死记硬背,用的时候拿一个中心是原点的方块想象一下就行了,这个顺序出来的效果是最符合人类直觉的。假如先旋转再缩放,方块会变斜了;如果先平移再旋转,那么方块的位置就不是那么直观能确定了。

齐次坐标的意义

个人感觉齐次坐标这个概念的引入加大了理解的难度。

所谓齐次坐标,简单点讲,就是在原有向量三维的基础上增加了一个维度。

先抛开这个概念,在三维变换中,增加一个维度的目的就是要把平移、旋转和缩放三个矩阵能用矩阵乘法来合成一个矩阵,空间变换可以用如下形式表示

P ′ = M ⋅ P M = M T ⋅ M R ⋅ M S 其中: M T :平移矩阵 M R :旋转矩阵 M S :缩放矩阵 \begin{aligned} & P^{'}=M \cdot P \\[2pt] & M=M_T \cdot M_R \cdot M_S \\[2pt] 其中:&\\ & M_T:平移矩阵 \\[2pt] & M_R:旋转矩阵 \\[2pt] & M_S:缩放矩阵 \end{aligned} 其中:P=MPM=MTMRMSMT:平移矩阵MR:旋转矩阵MS:缩放矩阵

这里要注意一下公式中的顺序。矩阵乘法是满足结合律的,点被乘在右边,所以按这个顺序才是先缩放,再旋转,最后平移。

这是我们平时见到的形式,下面就来讲一下齐次坐标的意义。

如果不用齐次坐标,空间变换的公式是这样的

P ′ = M R ⋅ M S ⋅ P + P T P^{'}=M_R \cdot M_S \cdot P + P_T P=MRMSP+PT

平移是个向量加法操作。变成齐次坐标,主要就是为了给矩阵增加一列来把这个加法包含进来,如下所示。

P ′ = [ M R ⋅ M S , P T ] ⋅ P P^{'}= \begin{bmatrix} M_R \cdot M_S, & P_T \end{bmatrix} \cdot P P=[MRMS,PT]P

但这个公式还不够完美,做完一次乘法后,点又由齐次坐标变为了普通坐标,不适合连续变换,也不适合显卡等硬件的实现。

所以再加一行,让乘完的结果也是齐次坐标,如下所示

P ′ = [ M R ⋅ M S P T 0     0     0 1 ] ⋅ P P^{'}= \begin{bmatrix} M_R \cdot M_S & P_T\\ 0 \space \space \space 0 \space \space \space 0 & 1 \end{bmatrix} \cdot P P=[MRMS0   0   0PT1]P

当然,齐次坐标还有更大的作用,我们规定齐次坐标转实际坐标的公式如下

齐次坐标: ( x , y , z , w ) 实际坐标 : ( x w , y w , z w ) 齐次坐标:(x, y, z, w) \\[8px] 实际坐标: (\frac{x}{w}, \frac{y}{w}, \frac{z}{w}) 齐次坐标:(x,y,z,w)实际坐标:(wx,wy,wz)

这样齐次坐标是可以表示无穷远点的(w为0)。

同样,它还可以处理例如世界坐标到屏幕坐标的映射等更加复杂的矩阵变换(w不等于1)。

平移矩阵

平移矩阵的公式如下:

[ 1 0 0 P T x 0 1 0 P T y 0 0 1 P T z 0 0 0 1 ] \begin{bmatrix} 1& 0 & 0 & P_{T_x} \\ 0& 1 & 0 & P_{T_y} \\ 0& 0 & 1 & P_{T_z} \\ 0& 0 & 0 & 1 \end{bmatrix} 100001000010PTxPTyPTz1

这个没啥好讲的,用矩阵乘法试下就知道它的作用了,如下所示

[ 1 0 0 P T x 0 1 0 P T y 0 0 1 P T z 0 0 0 1 ] ⋅ [ P x P y P z 1 ] = [ P x + P T x P y + P T y P z + P T z 1 ] \begin{bmatrix} 1& 0 & 0 & P_{T_x} \\ 0& 1 & 0 & P_{T_y} \\ 0& 0 & 1 & P_{T_z} \\ 0& 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} P_x\\ P_y\\ P_z\\ 1 \end{bmatrix}= \begin{bmatrix} P_x + P_{T_x}\\ P_y + P_{T_y}\\ P_z + P_{T_z}\\ 1 \end{bmatrix} 100001000010PTxPTyPTz1 PxPyPz1 = Px+PTxPy+PTyPz+PTz1

旋转矩阵

旋转矩阵的公式如下:

[ r 00 r 01 r 02 0 r 10 r 11 r 12 0 r 20 r 21 r 22 0 0 0 0 1 ] \begin{bmatrix} r_{00} & r_{01} & r_{02} & 0 \\ r_{10} & r_{11} & r_{12} & 0 \\ r_{20} & r_{21} & r_{22} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} r00r10r200r01r11r210r02r12r2200001

这里没有用角度的正余弦来表示,主要是为了方便大家理解。

设: e 0 = [ r 00 r 10 r 20 ] e 1 = [ r 01 r 11 r 21 ] e 2 = [ r 02 r 12 r 22 ] \begin{aligned} 设:& \\[2px] & e0 = \begin{bmatrix} r_{00} \\ r_{10} \\ r_{20} \\ \end{bmatrix} \\[2px] & e1 = \begin{bmatrix} r_{01} \\ r_{11} \\ r_{21} \\ \end{bmatrix} \\[2px] & e2 = \begin{bmatrix} r_{02} \\ r_{12} \\ r_{22} \\ \end{bmatrix} \\[2px] \end{aligned} 设:e0= r00r10r20 e1= r01r11r21 e2= r02r12r22

这个矩阵乘出来长这个样子

P ′ = P x ⋅ e 0 + P y ⋅ e 1 + P z ⋅ e 2 P^{'}=P_x \cdot e0 + P_y \cdot e1 + P_z \cdot e2 P=Pxe0+Pye1+Pze2

通过这个公式,我们可以把旋转矩阵理解为坐标系的旋转,e0、e1、e2就是旋转后新的坐标轴,P点的值是P'点在新坐标系下的局部坐标。

这样旋转矩阵的性质也就记住了:

  • e0、e1、e2都是单位向量
  • e0、e1、e2互相正交

关于旋转矩阵的更多知识,参考下面这篇文章

       通俗易懂的三维空间旋转矩阵、欧拉角、四元数

缩放矩阵

缩放矩阵的定义如下:

[ s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ] \begin{bmatrix} s_{x} & 0 & 0 & 0 \\ 0 & s_{y} & 0 & 0 \\ 0 & 0 & s_{z} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} sx0000sy0000sz00001

这个也不需要过多的解释,乘出来就懂了,如下所示

[ s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ] ⋅ [ P x P y P z 1 ] = [ s x ⋅ P x s y ⋅ P y s z ⋅ P z 1 ] \begin{bmatrix} s_{x} & 0 & 0 & 0 \\ 0 & s_{y} & 0 & 0 \\ 0 & 0 & s_{z} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} P_x\\ P_y\\ P_z\\ 1 \end{bmatrix}= \begin{bmatrix} s_{x} \cdot P_x\\ s_{y} \cdot P_y \\ s_{z} \cdot P_z \\ 1 \end{bmatrix} sx0000sy0000sz00001 PxPyPz1 = sxPxsyPyszPz1

三维矩阵变换的几何意义理解

三维空间变换,我们可以从坐标系统变换的角度来理。

下图演示的是一个二维的坐标变换就是一个坐标系到另一个坐标系的变换。三维是一样的,二维只是更好看清楚。

缩放实际是对坐标轴的缩放,也就是说,有缩放时,坐标轴有可能不再是单位向量,为了概念统一,下面的公式依然假设e0、e1、e2是单位向量,缩放系数单独处理。

三维变换的过程也就相当于根据局部坐标系下坐标计算世界坐标系坐标的过程,如下所示

P ′ = ( P x ⋅ s x ⋅ e 0 ,    P y ⋅ s y ⋅ e 1 ,    P z ⋅ s z ⋅ e 2 ) + P T P^{'}=(P_x \cdot s_x \cdot e0,\space\space P_y \cdot s_y \cdot e1,\space\space P_z \cdot s_z\cdot e2) + P_T P=(Pxsxe0,  Pysye1,  Pzsze2)+PT

这个公式也为我们提供了一个将三维变换矩阵拆解成移动、旋转和缩放的算法。

逆变换的过程相当于用世界坐标系的坐标计算局部坐标系的坐标的过程。

V = P ′ − P T P = ( V ⋅ e 0 s x ,    V ⋅ e 1 s y ,    V ⋅ e 2 s z ) \begin{aligned} & V=P^{'}-P_T \\[2px] & P=(\frac{V \cdot e0}{s_x}, \space\space\frac{V \cdot e1}{s_y}, \space\space\frac{V \cdot e2}{s_z}) \end{aligned} V=PPTP=(sxVe0,  syVe1,  szVe2)

这个公式也是快速计算三维变换矩阵逆矩阵的算法基础。

三维变换矩阵拆解算法和快速求逆算法,后续文章会做更详细的讲解。

Python面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将数据和操作封装在对象中,通过对象之间的交互实现程序的设计和开发。下面是一些关键概念,帮助你更好地理解Python面向对象编程。 1. 类(Class):类是对象的蓝图或模板,描述了对象的属性和行为。它定义了对象的特征和方法。例如,我们可以定义一个名为"Car"的类来表示汽车,其中包含属性(如颜色、型号)和方法(如加速、刹车)。 2. 对象(Object):对象是类的实例,是具体的实体。通过实例化类,我们可以创建一个对象。例如,我们可以创建一个名为"my_car"的对象,它是基于"Car"类的实例。 3. 属性(Attribute):属性是对象的特征,用于描述对象的状态。每个对象都可以具有一组属性。例如,"Car"类的属性可以包括颜色、型号等。 4. 方法(Method):方法是对象的行为,用于定义对象的操作。每个对象都可以具有一组方法。例如,"Car"类的方法可以包括加速、刹车等。 5. 继承(Inheritance):继承是一种机制,允许我们创建一个新类(称为子类),从现有类(称为父类)继承属性和方法。子类可以扩展或修改父类的功能。继承可以实现代码重用和层次化设计。 6. 多态(Polymorphism):多态是一种特性,允许不同类的对象对同一方法做出不同的响应。多态提高了代码的灵活性和可扩展性。 7. 封装(Encapsulation):封装是一种将数据和操作封装在对象中的机制,隐藏了对象的内部实现细节,只暴露必要的接口给外部使用。这样可以保护数据的安全性,提供了更好的模块化和代码复用性。 通过理解这些概念,你可以更好地掌握Python面向对象编程。在实践中,你可以使用类来创建对象,操作对象的属性和调用对象的方法,通过继承和多态实现代码的灵活性和可扩展性,通过封装保护数据的安全性和提高代码的可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值