3D图像算法从入门到进阶(包含C实现)
3D图象算法 3D简介 我们首先从坐标系统起先。你或许知道在2D里我们常常运用笛卡儿坐标系统在平面上来识别点。我们运用二维(X,Y):X表示水平轴坐标,Y表示纵轴坐标。在3维坐标系,我们增加了Z,一般用它来表示深度。所以为表示三维坐标系的一个点,我们用三个参数(X,Y,Z)。这里有不同的笛卡儿三维系统可以运用。但是它们都是左手螺旋或右手螺旋的。右手螺旋是右手手指的卷曲方向指向Z轴正方向,而大拇指指向X轴正方向。左手螺旋是左手手指的卷曲方向指向Z轴负方向。事实上,我们可以在任何方向上旋转这些坐标系,而且它们仍旧保持本身的特性。在计算机图形学,常用坐标系为左手坐标系(手背向上),所以我们也运用它。: X 正轴朝右 Y 正轴向上 Z 正轴指向屏幕里 矢量 什么是矢量?几句话,它是坐标集合。首先我们从二维矢量起先,(X,Y):例如矢量P(4,5)(一般,我们用->表示矢量)。我们认为矢量P代表点(4,5),它是从原点指向(4,5)的有方向和长度的箭头。我们谈论矢量的长度指从原点到该点的距离。二维距离计算公式是 | P | = sqrt( x^2 + y^2 ) 这里有一个好玩的事实:在1D(点在单一的坐标轴上),平方根为它的肯定值。让我们探讨三维矢量:例如P(4, -5, 9),它的长度为 | P | = sqrt( x^2 + y^2 + z^2 ) 它代表在笛卡儿3D空间的一个点。或从原点到该点的一个箭头代表该矢量。在有关操作一节里,我们探讨更多的学问。 矩阵 起先,我们从简洁的起先:我们运用二维矩阵4乘4矩阵,为什么是4乘4?因为我们在三维坐标系里而且我们须要附加的行和列来完成计算工作(本质缘由:在计算机图形学里应用的图形变换,事实上是在仿射空间而不是向量空间中进行的)。在二维坐标系我们须要3乘3矩阵。着意味着我们在3D中有4个水平参数和4个垂直参数,一共16个。例如: 4x4单位矩阵 | 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 0 0 0 1 | 因为任何其它矩阵与之相乘都不变更,所以称之为单位阵。又例如有矩阵如下: | 10 -7 22 45 | | sin(a) cos(a) 34 32 | | -35 28 17 6 | | 45 -99 32 16 | 有关矢量和矩阵的操作 我们已经介绍了一些特别简洁的基本概念,那么上面的学问与三维图形有什么关系呢? 本节我们介绍3D变换的基本学问和其它的一些概念。它仍旧是数学学问。我们要探讨有关矢量和矩阵操作。让我们从两个矢量和起先: ( x1 , y1 , z1 ) + ( x2 , y2 , z2 ) = ( x1 + x2 , y1 + y2 , z1 + z2 ) 几何意义:等于两个矢量组成的平行四边形的长对角线的矢量 两个矢量减法的几何意义:等于两个矢量组成的三角形的另一条边的矢量 很简洁,现在把矢量乘于系数(数乘): k?( x, y, z ) = ( kx, ky, kz ) 几何意义:将矢量进行缩放 点积如下表示:(点积是一个标量) (x1 , y1 , z1 ) ?( x2 , y2 , z2 ) = x1x2 + y1y2 + z1z2 事实上,两个矢量的点积被它们的模的乘积除,等于两个矢量夹角的余弦(两个矢量的模与其夹角的余弦之积称为两个矢量的数量积(或称内积、点积))。所以 cos (V ^ W) =V ?W / | V | | W | 几何意义:两个矢量的点积衡量着两个向量的角度关系。在物理上的意义假如两个矢量分别代表力和位移,那么两个矢量的点积就是功。 留意“^“并不表示指数而是两个矢量的夹角。点积可以用来计算光线与平面的夹角,我们在计算阴影一节里会具体探讨。 现在探讨叉乘: ( x1 , y1 , z1 ) X ( x2 , y2 , z2 ) =( y1z2 - z1y2 , z1x2 - x1z2 , x1y2 - y1x2 ) 几何意义:叉乘的结果是一个伪向量,但是他的模是以此二向量为相邻两边的平行四边形面积 叉乘对于计算屏幕的法向量特别有用。 OK,我们已经讲完了矢量的基本概念。我们起先两个矩阵的和。它与矢量相加特别相像,这里就不探讨了。设I是矩阵的一行,J是矩阵的一列,(i,j)是矩阵的一个元素。我们探讨与3D变换有关的重要的矩阵操作原理。 矩阵相乘的几何意义:把两次线性变换合成一次 两个矩阵相乘,而且M x N N x M。例如:(矩阵乘法是有依次的) A B 4x4矩阵相乘公式 假如 A=(aij)4x4, B=(bij)4x4, 那么 A x B= | S> a1jbj1 S> a1jbj2 S> a1jbj3 S> a1jbj4 | | | | S> a2jbj1 S> a2jbj2 S> a2jbj3 S> a2jbj4 | | | | S> a3jbj1 S> a3jbj2 S> a3jbj3 S> a3jbj4 | | | | S> a4jbj1 S> a4jbj2 S> a4jbj3 S> a4jbj4 | 其中 j=1,2,3,4 而且假如 AxB=(cik)4x4 那么我们可以在一行上写下: cik = S>4, j=1 aijbjk ( a1, a2, a3 ) x B = (Sum(aibi1) + b4,1, Sum(aibi2) + b4,2, Sum(aibi3) + b4,3 ) 现在,我们可以试着把一些矩阵乘以单位矩阵来了解矩阵相乘的性质。我们把矩阵与矢量相乘结合在一起。下面有一个公式把3D矢量乘以一个4x4矩阵(得到另外一个三维矢量)假如B=(bij)4x4,那么: ( a1, a2, a3 ) x B = (S>aibi1 + b4,1, S>aibi2 + b4,2, S>aibi3 + b4,3 )> 这就是矢量和矩阵操作公式。从这里起先,代码与数学之间的联系起先清晰。 变换 我们已经见过象这样的公式: t( tx, ty ): ( x, y ) ==> ( x + tx, y + ty ) 这是在二维笛卡儿坐标系的平移等式。下面是缩放公式: s( k ): ( x, y ) ==> ( kx, ky ) 旋转等式: r( q ): ( x, y ) ==> ( x cos(q) - y sin(q), x sin(q) + y cos(q) ) 以上都是二维公式,在三维里公式的形式仍旧很相近。 平移公式: t( tx, ty, tz ): ( x, y, z ) ==> ( x + tx, y + ty, z + tz ) 缩放公式: s( k ): ( x, y, z ) ==> ( kx, ky, kz ) 旋转公式(围绕Z轴): r( q ): ( x, y, z ) ==> ( x cos(q) - y sin(q), x sin(q) +