3D游戏编程入门(八)计算机图形学
07年到来了,新的一年并没有带了更多的欣喜感,只有年龄又大了一岁,压力更沉重了一份,于是积累知识也更显的紧要了.07年,加倍奋斗的一年.
07年第一个早上竟是被梦惊醒的,梦里有朋友到博客中留言大骂我没有继续写3D游戏编程,没有信用,正准备辩解,愤怒的朋友却不知哪儿弄了个木棒子打中我后脑勺,吓醒后发现原来是挂着的衣服掉在脸上了,遮的我透不过气来.仔细想想,写的这些东西始终无法与正规书籍相行比较,相信愿意看的人也不多,但它确实为我个人的复习带来极大的好处,令我记性好了很多,所以我还会继续.相信梦中那强烈的负罪感也不是毫无根据的袭来吧,呼
趁着元旦放假三天,我将全部精力投入到3D复习中,预计每日能放出5篇左右的日志吧,3天15节应该可以说完顶点,纹理,灯光,相关部分吧。因为这里整体把握不好,我会从各个方面重点进行反复的复习和说明。
恩,开始正题
#计算机图形学
###向量
了解DirectX之前,我们有必要了解这部分知识
计算机图形学主要是研究使用计算机及其图形设备来输入,表示,变换,运算和输出图形的原理,算法及系统的学科。
从定义中我们可以看出,我们的基本步骤可以分为5步,输入源图形,结构表示图形属性,变换矩阵,运算矩阵,输出目标图形。我们了解的重点则是相关的运算原理,优化其中的算法,以及熟悉整个渲染系统流程。
我们首先来了解下计算机图形设备,我们可以看下面的图,首先我们从外围设备进行输入数据,系统总线将这部分数据根据类别或放置于系统存储器中,或发送到CPU中,或发送到显存GPU中,再根据显卡中的相应运算,将其发送视频控制器中,显示器将其显示出来。我们最需要重视的则是数据如何存放于CPU,GPU中,又是如何进行运算后进行输出的。
在3D游戏编程中,我们使用图形编程的首要任务是要模拟真实世界中物理的各种属性,给玩家以真实感。这些属性包括着物体的形状,纹理,材质,物体间的相对位置,遮挡关系,骨骼运动效果等。我也将按照这个流程进行复习和讲述。
我们大致了解下图形学需要知道的东西,接下来将对其几何概念和运算进行说明。这部分需要一定的空间想象能力和线性代数或者立体几何的知识,当然,即使你不了解这些细节也没有大的关系,因为它们并非想象中的复杂。
首先我们来理解一下向量。在高中物理中我们应该知道矢量和向量的区别,前者是没有方向的线段,后者是有方向的线段。我们物理中的各种力全是用向量来描述的。向量的两大特性就是:有长度,和有方向。当两个向量在空间中,方向相同且长度相同,我们就认为它们是相等的,即使在图上相对描绘位置不同也没有关系,因为我们并不关心它的位置关系。所以无论一个向量如何进行平移,我们都认为它是不变的,因为它的两个属性没有发生变化。
但当这个向量尾部和坐标系统的原点一致时,向量就处于标准位置。这里要和标准向量进行区别,标准向量的定义是,长度为1的向量就成为一个标准单位向量,这里希望大家记清楚。
当我们已经获得一个标准位置的向量时,我们相当于已经获得了一个向量的尾顶点(0,0,0),向量是一个有方向的线段,而线段是由两个点即可确定的,我们仅需要再获得向量的顶点坐标,我们就可以得到这个向量的长度,和它的方向,所以我们在二维世界中,可以用这样的模式确定一个向量U = ( Ux, Uy ),想象一下,尾顶点为( 0,0 ),头顶点为( Ux, Uy )的向量是否是确定的唯一的?而三维坐标中我们同样而已这样表示一个向量N = ( Nx, Ny, Nz )。当然这样写出来很容易让人混淆,这是一个点还是一个向量?我们必须再从定义上来区别两者,点是一个坐标系中一个位置,而向量拥有着长度和方向。
三维坐标系这里要提一下,我们3D游戏编程中通常使用的左手坐标系,即左为X轴正方向,上为Y轴正方向,里为Z轴正方向(即你的屏幕向里面是正方向,所以我们眼睛的Z坐标一直是负的)。为方便大家理解,我们下面继续给出图示。其中i,j,k三个向量我们假设长度都为1,则可以分别表示为(1,0,0),(0,1,0),(0,0,1),因为它们的长度为1,我们可以称其为单位向量,又因为它们的方向特殊,正沿三轴伸展,我们又称其为基本向量。
在二维世界中,我们计算一个线段的长度是如何进行的呢?我们假如由(0,0)点和(4,5)点为两顶点的线段,我们求其长度,应该是(4-0)的平方+(5-0)的平方再开2倍根号吧。而三维中,假如向量的尾顶点为坐标原点(0,0,0)头顶点为(4,5,6),则其长度也为(4-0)的平方+(5-0)的平方+(6-0)的平方,最后开2倍根号。我们称向量的长度为它的模。因为我说过,向量在坐标系中无论如何平移,它的方向和长度两大属性是不变的,我们终究把它看成相等的。这时我们一定可将任意一个向量进行平移,最终总会获得一个尾顶点为坐标原点的相等向量,则我们通过获得它的顶点坐标可以获得该向量的模。我们可以举例:一个尾坐标为(1,2,3)顶坐标为(4,5,6)的向量,经过平移后,它将变成一个尾坐标为(0,0,0),头顶点坐标为(3,3,3)的相等向量(你可以去想想,是否改变了此向量的方向和长度)。再求它的摸,则为3的平方+3的平方+3的平方,再开2次根,结果为3倍根号3。
当我们获得了一个向量的模后,我们再将其除以其模,则可获得一个长度为1方向不变的单位向量(注意,不是标准向量)。依旧拿(1,2,3)(4,5,6)这个向量来举例,平移后该向量为N(3,3,3),模为3倍根号3,拿Nx=3,Ny=3,Nz=3除以模,则其单位向量是(根号3/3,根号3/3,根号3/3),你可以计算下,其长度是否为1,方向是否为1。
我们获得一个向量的单位向量是很重要的,学过线形代数的朋友可以去想想当一个矩阵乘以一个单位矩阵会发生什么变化。这些我后面会再详细说明其重要性。
学过物理力学的朋友应该回想一下,当一个物体受两个力的作用时,我们是如何算出其合力的?这里涉及的东西较杂,我不再详细解释。给出大家一个图,大家可以参考回忆下,我直接给出两向量相加相减的公式了
U + V = ( Ux+Vx, Uy+Vy, Uz+Vz );
U - V = ( Ux-Vx, Uy-Vy, Uz-Vz )
就如开始我们去除模的道理一样,当我们将一个向量和一个标量(无方向的长度)相乘时,向量的长度大小会变化,其方向不变化(若乘的是负数,则反向),我们获得的新向量也可求出,公式如下
V = kU = ( kUx, kUy, kUz );
当我们记住并理解上述基本公式后,我们可以接下来理解下向量的点乘和叉乘。
点乘公式为S = U 点乘 V = U的模 乘以 V的模 再乘以 COS(UV之间的角度) 这样得出来的是一个标量S,是没有方向的值。但是根据这个值与0的比较,我们可以获得U,V两标量之间的关系。
如果 =0,那么向量 u . v 相等。
如果 >0,那么向量 u 、v 之间的夹角小于90度。
如果 <0,那么向量 u 、v 之间的夹角大于90度。
我们可以自己想想为什么。
叉乘在我们设置法线时非常重要,大家应该很好的记住这里
首先叉乘公式为:S = U 叉乘
V = [( UyVz - UzVy ),( UzYx - UxVy ),( UxVy - UyVx)];
我们从中可以看出,我们叉乘得到的不再是一个无方向标量值。而是一个向量。那么这个向量是什么样的向量呢。我们看下图
我们应该去记住,两个向量叉乘得到的是一个同时垂直于这两个向量的一个新向量。恩,具体的道理,实在难以解释,自己无法理解的朋友还是死记吧。>_<
###矩阵
恩,懂得编程的朋友应该清楚数组,学过几何线性代数的朋友应该清楚矩阵,其实个人认为这两者没有任何区别,起码在D3D编程中很难去找到什么区别。
这两者都是以一个M行N列的矩形数字数组去记录一系列的数字。我们常称M,N为此矩阵的维数。当两个矩阵的维数和其中元素都相同时,我们称它俩是相等的。
当一个矩阵只有一个单行或者一个单列时,我们称其为行向量或列向量。我们的一个三维向量坐标就是一个三列的行向量。
#####矩阵的加减法。
首先我们要求这两个矩阵的维数必须相等,否则我们无法去进行这种运算。矩阵的和就是两个矩阵中对应位置的元素相加得到一个新的矩阵。
#####矩阵的数乘法。
就是用一个矩阵和一个标量数字相乘。我们将此矩阵中的所有元素分别与此数字相乘得到的一个新的矩阵就是矩阵的数乘。
#####矩阵的相乘。
即矩阵A乘以矩阵B。首先,我们要求矩阵A的列数和矩阵B的行数必须相等,即前列后行相等的要求。从这里我们应该明白,AB是不等于BA的,矩阵相乘是很注意前后顺序的,它不满足乘法交换律。这里公式不好写,我建议大家去网上简单找个线形代数的资料看下。
#####单位矩阵。
我们开始说过三个标准向量,并且给了图,当我们将i,j,k三个向量顺序排列,则是一个三维标准单位矩阵。任何矩阵乘以一个单位矩阵都不会进行任何改变,它是一个仅主对角线为1,其他元素均为0的特殊矩阵。
#####逆矩阵。
仅有行列数相等的方矩阵才会有逆矩阵,它即是将矩阵中的所有元素相对与主对角线进行位置互换的矩阵,我们可以理解成,将元素的行列下标进行替换得到的矩阵。一个方矩阵和它的逆矩阵相乘时,结果会是一个单位矩阵。
#####转置矩阵。
和逆矩阵不同的是,它适用于任何行列的矩阵,但它也是将一个矩阵的行列进行交换,一个mXn的矩阵,转置矩阵则是nXm的矩阵。
#####矩阵的齐次坐标变换。
我们说过,矩阵相乘是有要求的,它要求我们前矩阵列数和后矩阵行数相等,假如我们现在拥有一个2X2的矩阵,一个3X3的矩阵,我们是无法直接进行乘法运算的,这就要求我们将2X2的矩阵列数变成3,此矩阵变成2X3的矩阵才能参与运算,这时我们可以在新添加的这列中两个元素都补0,获得一个新的2X3的矩阵,这就是矩阵的齐次坐标变换。它是为了方便我们的矩阵乘法运算而存在的。
###图形变换
说完了向量矩阵,我们可以联系游戏来说明下图象变换。
图象的变换一般是分为三类的,旋转,平移,缩放。
而在二维游戏中,我们比较少用缩放,因为它原本就没有深度概念,我们可以想想《传奇》里是否有人物越走越远时是否有变小?三维游戏中,这三者都会有很深的涉及。
因为二维游戏比较容易,我们先拿它进行举例。
首先我们要清楚,一个图象在屏幕上,它原本就是由一个个象素组成的,而一系列的象素点就组成了一个矩阵,当我们想对图象进行翻转,缩放,平移等,则需要对它的矩阵点进行运算就可以获得改变后的图象了。这是基本原理。
一般来说,我们是将图象的矩阵乘以一个变换矩阵来获得改变后的图象矩阵。
二维变换矩阵是一个三行三列的矩阵,其中a11,a12,a21,a22是对图形进行旋转,缩放,对切变换的。a13,a23是对图形进行投影变换的,它将控制灭点的生成.a31,a32是控制图形的平移变化.a33是控制图形缩放的。大家有兴趣的话,可以自己设置一个简单的矩阵组,其中每一点记录三个数值,x坐标,y坐标,和该点颜色,再和不同的二维变换矩阵相乘,获得新矩阵,看看变化情况。
三维变换矩阵则是由一个四行四列的矩阵构成。
此矩阵中a41控制图形x轴平移度,A42控Y轴平移量,A43控制Z轴平移量。A11,12,13,21,22,23,31,32,33均控制图形的旋转轴和角度。缩放则由A11,A22,A33分别控制x,y,z的缩放度。
如何,是否一片晕晕的,呵呵,其实这些基本的东西进行了解就好,没必要去严格的死记,在之后的深入研究才会真正有些用处的。暂时没有消化也不成大问题的。别放弃。不清楚的可以留言问下:)