上次说到渲染管线的一般组成,接下来就要说说各部分的转换怎么做了。
在这之前,本着扫盲的态度,先介绍一点矩阵的基础知识。
大学一年级一般都会上一门叫做“线性代数”的课,这个课上就会讲很多关于线性方程组(可以先不管“线性”两个字,初等数学里的东西基本都是线性的),关于矩阵的东西。
首先,什么是线性方程组?
ax + by + c = 0 a b c
dx + ey + f = 0 这个就是一个线性方程组, d e f
gx + hy + i = 0 我们可以把它表示成矩阵 g h i
再来,什么是向量?一个1 x N 的矩阵,就是一个向量,例如
a
b 一般可以记成(a,b,c)
c
线性代数对矩阵定义了一系列的运算方法,比如乘法,加法等。具体的定义最好找本线性代数来看看,另外推荐一个《理解矩阵》,是个短小精悍的文章,对于理解矩阵,坐标系,向量比较有好处。
现在就先说明几个问题。
1、一个N维向量,可以表示一个N维空间的点。比如说(1,2)在平面直角坐标系表示x=1,y=2的点
2、可以同时存在多个坐标系。例如,有两个坐标系,重叠在一起,但是坐标系A的单位长度是坐标系B单位长度的2倍。那么在A坐标系中的 (1,0)点,在B坐标系中就是 (2,0)点
3、坐标系原点位置可以不同。比如,坐标系A原点在坐标系B的 (1,1)处,那么坐标系A的(1,0)点就是坐标系B的(2,1)点。
4、坐标系可以表示成矩阵。 比如 2 0 就表示一个x轴缩小一半的坐标系。这个坐标系实际上是由
0 1
两个向量 2 和 0 放在一起组成的,没错,也就是坐标轴的单位向量值的倒数组成了坐标系。所以很显
0 1
然,1 0就是一个我们平常使用的坐标系。至于另外那两个数要是不为0会发生什么情况,可以自己想
0 1
想,我后面也会解释。
5、三维空间的坐标系可以表示成3x3矩阵。(这个不用解释了吧)
6、坐标系矩阵与对应维数的向量相乘,将得到该向量在这个坐标系下的表示。这个是最关键的一个点,能理解,后面就都好办了。一个向量 (2,2,2) ,一个矩阵(坐标系)2 0 0 ,用矩阵乘以这个向量,
0 2 0
0 0 2
根据矩阵乘法,我们将得到向量(4,4,4) 。关于这一点,大家可以看看《理解矩阵》,它的描述比我说得更透彻,其实矩阵还表达了一种映射关系,或者表达了一种变换。
7、坐标系矩阵还可以扩展,用来表示坐标系原点的位置。这种扩展的坐标系矩阵看起来就像这个样子1 0 0 1 这是就是所谓的“三维空间的齐次坐标系”。为什么叫“齐次”,我还没理解透,以后理解
0 1 0 1
0 0 1 0
0 0 0 1
了再补上。这个矩阵描述的坐标系是这样的: 坐标系的x,y,z轴的单位向量都与我们最常见的那种坐标系一样,原点在(-1,-1,0)处。也就是,最右边一列多出来的,就是表达原点位置的向量。那么这个矩阵怎么做乘法呢,因为根据矩阵乘法,这个矩阵需要乘以一个4维向量。假设有一个点(1,1,1),那么我们就在这个向量后面再增加一个数,变成 (1,1,1,1),然后就可以去乘这个矩阵了(关于这个硬加上的数,见下一点)。
8、上面说到齐次坐标系,还说到了一个三维向量增加一维变成4维,那么这个第四维是什么含义呢?当一个向量表达齐次坐标时,它的最后一维有特殊的含义。一个4维向量V (a,b,c,h),当h = 0 时,V表示一个三维空间中的向量。当h 不为 0 时,V表示一个三维空间中的点。这个点的坐标是 (a/h,b/h,c/h)。在进行矩阵运算时,第四维正常的参与运算,我们可以得到简单的推论:
向量加向量得到向量。 向量得到点。 点加点得到中点。
在此补充一点,在空间中,“点”和“向量”其实是不同的概念,向量有方向,但没位置,点有位置但没方向。所以在齐次坐标系矩阵中,第四列第四行是1,因为原点是一个点,不是向量。
9、在计算机图形学中,一般就是用矩阵来做各种物体的坐标变换,方法很简单,就是用一个矩阵去乘以表示坐标的向量。
10、矩阵的表示方法还有一种,就是向量按行表示,线性方程组矩阵就是这样。也就是一行表示一个向量。所以看其它资料的时候要注意一下。
说了一这么些数学,估计也看烦了,那么就先讲一个实例:世界坐标变换。
世界坐标变换是渲染管线生成世界模型时的必备操作。
比如说,我有一个正方体,顶点坐标为(1,1,1),(1,1,-1),(1,-1,1),(1,-1,-1),(-1,1,1),(-1,1,-1),(-1,-1,1),(-1,-1,-1)。 然后我需要在这个世界模型中放置很多个正方体,怎么办呢?总不能手工的去输入那么多的坐标吧。我只能对这个正方体作一些变换,比如:放大缩小,旋转,移动。通过这样一些操作,我就可以把这个正方体放到任何地方了。那么现在简单说怎么实现。
这个正方体,我们存储的时候就存下8个点就够了,这8个点都各自是一个4维齐次向量,可以用静态数组来实现。然后构造一个矩阵,依次乘以这8个点,那么一次变换就算做完了。
放大缩小,我们就构造这样的矩阵 2 0 0 0 ,这样就把正方体放大一倍
0 2 0 0
0 0 2 0
0 0 0 1
旋转: 这个相对比较复杂一点,在这里的旋转我们会说 绕x轴旋转 a 弧度(角度),相应的矩阵为
1 0 0 0
0 cosa sina 0
0 -sina cosa 0
0 0 0 1
平移: 把正方体中心移动到(1,2,3),矩阵为 1 0 0 1
0 1 0 2
0 0 1 3
0 0 0 1
一般情况下我们应该按照这样的顺序来做这三种变换: 缩放、旋转、平移。 如果改变顺序,那么转换出来的效果也将不一样,有兴趣的可以自己计算一下。
暂时就这么多吧,下次继续说~