过了个年,没学到什么好东西可以分享的,就把最近的成果总结一下,依然身为菜鸟的我,希望能抛砖引玉,求各位指点交流。
《DirectX 9.0 3D游戏开发编程基础》一书中,第二章讲述了流水线的一般步骤,第三章,用实例告诉大家如何绘制一个基本的3D图形。我们知道3D模型是由无数的多边形(例如三角形)组成的。所以绘制3D场景,就要涉及到一些多边形的问题,还有一点就是坐标问题,3D图形处理比较难的就是各种坐标之间的转换,需要我们深刻理解和掌握一些基本的坐标,并知道如何去利用这些坐标转换来达到我们想要的效果。
那么首先我们就从认识一些基本的概念开始吧。刚才提到多边形的问题,还有坐标的问题,两个结合起来,诞生了一些基本的概念,例如顶点(Vertex),索引(Index)等等,顶点就是多边形(下面我们用三角形做示范,后面不再重复强调)的坐标,而一个3D物体是由许许多多的三角形组成,那么我们可以想到,这些三角形的顶点肯定有共用的,也就是相邻的三角形的顶点一定出现共用的情形,那么,一旦有共用情况,我们还要去描述一遍顶点的坐标,显得冗余麻烦不方便,为此,引入了索引的概念,这样,顶点只用描述一次,而索引则可以重复的用来描述三角形。例如要绘制一个立方体,如图1所示:
图1
图1中的立方体有6个面,每个面上我们用两个三角形拼接而成,可以看到这些三角形有共用的顶点。那么我们怎么用顶点坐标和索引来描述他们呢?不考虑观察的角度,假设顶点坐标分别是Vertex[8]=(-1,-1,-1),(-1,-1,1),(-1,1,-1),(-1,1,1),(1,-1,-1),(1,-1,1),(1,1,-1),(1,1,1),由图中立方体可知,我们需要绘制6*2=12个三角形,每个三角形的顶点都要用索引表示出来,所以一共需要12*3=36个索引,即Index[36],那么三角形就可以表示了:
立方体正面的两个三角形, Index[0]=Vertex[0],Index[1]=Vertex[1],Index[2]=Vertex[2]; Index[3]=Vertex[0],Index[4]=Vertex[2],Index[5]=Vertex[3];
立方体背面的两个三角形,Index[6]=Vertex[4],Index[7]=Vertex[5],Index[8]=Vertex[6]; Index[9]=Vertex[4],Index[10]=Vertex[6],Index[11]=Vertex[7];
.................(同理可表示出其他面的三角形)
理解了这些基本概念之后,我们就可以认识流水线(Pipeline)了,要想绘制3D图形,一般来说需要遵从一定的步骤,这些步骤就是绘制流水线基本步骤。局部坐标系(local space)->世界坐标系(world space)->观察坐标系(view space)->背面消隐(backface culling)->光照(lighting)->裁剪(clipping)->投影(projection)->视口坐标系(viewport space)->光栅化(rasterization)。对于这些坐标系的认识,想快速认识一下的,请阅读博客 http://blog.csdn.net/trojanpizza/article/details/6652533 ,我这里省点事,想详细认识一下的,还是参考书籍比较好;背面消隐,就是把三角形区分正面和背面朝向,然后把朝向背面的部分消去不画在屏幕上,这样可以实现遮挡的效果;光照,顾名思义,就是表现3D图形的光源照射在物体表面的情形;裁剪和消隐作用相似,但作用不同,裁剪是将可见区域之外的部分删掉,不区分正面背面;投影是把n维映射到n-1维变换,而3D图形学中为了获得近大远小的透视效果就用到了投影。投影变换的公式很复杂,大家可以去查看相关论文或者著作(3D图形学部分);光栅化就是绘制前面准备好的每一个三角形的步骤。光栅化之后,我们就可以看到一个一个三角形组成的物体了。
下面上代码(链接在最下面),编译环境是VS2010,DX9.0的编译环境配置,在笔记(2)中提到了,一般没有什么问题,都可以通过的。运行效果如下:
图2
这里最后啰嗦一下,这个立方体一个面用了3个三角形~大家拿到代码后可以自行改动~达到想要的效果。
代码的工程文件:度盘 http://pan.baidu.com/s/1c0vV0NA 编译环境是 VS2010 环境已经配置好了,下载后即可编译~