我们都知道,在3D图形学中,所有的变换都可以划分为三种最基础的变换方式,分别为:
通过对这三种变换进行组合,就能够实现任意的变换形式。
在3D坐标下,如果向量使用3D向量表示的话,对于这三种变换的处理方式如下:
也就是说,这三种变换的处理方式是不同的,旋转和缩放变换能够通过乘法实现,而平移需要通过加法来实现。
所以图形学的大师们,觉得这样的计算方法十分的繁琐,他们希望能够使用一种统一的方式来对坐标进行变换。所以他们决定,将平移变换也使用乘法来统一这种计算方法。
所以,就提出了齐次坐标的概念。
齐次坐标,即使用N+1维的空间向量来表示N维的向量。通过这样的方法就能够使用乘法对平移变换也进行计算。
而平移变换对向量是没有用处的,只有对点才有用。所以就出现了齐次坐标(x,y,z,w),其中当w等于1的时候,表示的是点向量,0的时候,表示的就是普通向量。
在明白了齐次坐标之后,我们来看看什么是仿射变换。
从学习3D以来,就经常听到说3D图形学里面的变换都是仿射变换。以前也查过这个概念,但是过不了多久就忘记了。主要就是因为没有深刻的理解到这个概念的意义,所以就很容易遗忘掉它。直到今天遇到了问题,才深刻的理解仿射变换时什么样的变换。
仿射变换的定义如下:先进行线性变换,在进行平移变换的变换称之为仿射变换。注意这个定义里面,具有先后关系,我就是忽略了这个先后关系才对很多变换,搞的迷迷糊糊的。
在3D中,所谓的线性变换,指的就是旋转变换和缩放变换这两种。也就是说,我们在3D游戏开发中,使用的矩阵变换,实际上是一种仿射变换,它会先对向量进行旋转和缩放(这两种变换的先后顺序,无关紧要),然后在对向量进行平移操作。
这就是仿射变换的定义。一定要牢记,仿射变换时具有先后关系的两种变换的联合。
在学校学习线性代数的时候,那时候还是很清楚什么是正交矩阵。但是抛去了课本,就忘记了什么是正交矩阵。依稀只记得好像是任意两个行向量相乘的结果为0,也就是相互垂直的关系。今天也一直以这个定义来推导正交矩阵求逆运算的简化步骤,发现总是得不出正确的结果。所以,就重新学习了下什么是正交矩阵。
正交矩阵的定义:
a.矩阵中的任意两个行向量的乘积为0b.矩阵中每一个行向量都是单位向量
没有经过缩放的旋转矩阵就是一个正交矩阵。
数学上对矩阵的求逆运算,在学习线性代数的时候,一直就不知道为毛搞这么一个东东。(这也体现了中国填鸭式教育,先交给你是这么做,至于为什么这么做,以后才知道)直到自己学习游戏开发,特别是进行3D变换的时候,才明白了。
在3D中,变换都是通过矩阵来实现的。比如一个矩阵的功能是先让某个向量旋转A角度,在平移B距离。那么这个矩阵的逆矩阵的效果就应该是先让向量平移-B距离,然后在旋转-A角度。也就是说,矩阵和它的逆矩阵对向量进行的变换效果是相反的过程。
在学习3D游戏编程的过程中,经常会遇到一个问题,在解决某种变换的时候,网上给出这个变换的矩阵总是有两种不同的格式,他们互为转置。我以前一直不明白怎么回事。直到自己在学习OpenGL(先学DirectX)之后,才明白原来是两个标准3D API对于向量的定义方式不同导致的。
当我们讲解某个变换的时候,作者大多使用自己熟悉的方式来进行讲解。熟悉DirectX的人,会使用行向量的方式对矩阵进行描述,熟悉OpenGL的人,会使用列向量的方式对矩阵进行描述。所以就会导致出现两个相互为转置的矩阵出现。
比如说,在DX中,一个向量实际上是这样的:[x,y,z,w]
它在进行矩阵乘法的时候,是这样的:[x,y,z,w] * M (右乘矩阵的方式)
而对于OpenGL来说,它的向量表示是这样的:
[x,
y,
z,
w]
它在进行矩阵乘法的时候,是这样的:
M * transpose[x,y,z,w] (左乘矩阵的方式)
所以,这就导致了理解上的偏差。初学者最好弄明白这些基础的概念。
前面讲了一大堆,就是为了得出怎么样快速的求出一个正交矩阵的逆矩阵出来。
这里统一使用OpenGL的矩阵表示方法。
假如有一个矩阵:
[m00 m01 m02 m03]
[m10 m11 m12 m13]
[m20 m21 m22 m23]
[0 0 0 1]
在3D中这个矩阵有两个不同的部分构成,
一个是:
[m00 m01 m02]
[m10 m11 m12]
[m20 m21 m22]
的旋转矩阵R(由于是正交矩阵,这里就只能是未进行缩放的单位向量的正交旋转矩阵)
另外一个就是:
[1 0 0 m03]
[0 1 0 m13]
[0 0 1 m23]
[0 0 0 1]
的平移矩阵
这两个部分构成。
也就是可以简化为如下的矩阵表示:
[R T] * V
[0 0 0 1]
前面说过,要想求一个矩阵的逆矩阵,就是构造一个具有相反效果的矩阵即可,那么上面的矩阵是一个仿射矩阵,它是先进行R旋转,然后在进行T平移操作,所以它的逆操作就应该是:
先平移-T,然后在旋转-R
所以得出下面的矩阵:
[Transpose_R] * [Transpose_T]
[0 0 0 1] [0 0 0 1]
由于R是正交矩阵,正交矩阵有一个特性:
正交矩阵的逆矩阵等于转置矩阵
所以就能够很直观的得出正交矩阵构成的仿射矩阵的逆矩阵了。