这次主题是渲染管线。它是用来创建为3D世界进行几何描述的2D图形并设定一个虚拟照相机确定这个世界中哪一部分将被透视投影到屏幕上。
\
2.1表现模型
一个场景是多个物体或模型的集合。一个物体可以用三角形网格(triangle mesh)来近似表示,如图2.2所示。由三角形网格建立一个物体,我们称之为建模。3D世界中最基本的图元就是三角形,但是Direct3D也支持点图元和线图元但我们都不常用到。一个多边形的两边相交的点叫做顶点。为了描述一个三角形,我们通常指定三个点的位置来对应三角形的三个顶点(如图2.3),这样我们就能够很明确的表示出这个三角形了。
2.1.1 顶点格式
我们以前定义的点在数学上来说是正确的,但是当我们在Direct3D环境中使用它的时候就会觉得很不完善。这是因为在Direct3D中的顶点包含了许多附加的属性,而不再单纯的只有空间位置的信息了。例如:一个顶点可以有颜色和法线向量属性。Direct3D让我们可以灵活的构造自己的顶点格式。换句话说,我们可以自己定义顶点的成员。
为了创建一个自定义的顶点结构,我们首先要创建一个包含能存放我们选择的顶点数据的结构。例如,下面我们举出两种不同顶点数据类型的例子,一种包含了位置和颜色信息,第二种则包含了位置,法线向量,纹理坐标信息。
struct ColorVertex
{
float _x, _y, _z; // 位置
DWORD _color; // 颜色
};
struct NormalTexVertex
{
float _x, _y, _z; // 位置
float _nx, _ny, _nz; // 法线向量
float _u, _v; // 纹理坐标
};
一旦我们有了完整的顶点格式,我们就要使用灵活顶点格式(FVF)的组合标志来描述它。例如第一个顶点结构,我们要使用如下的顶点格式:
#define FVF_COLOR (D3DFVF_XYZ | D3DFVF_DIFFUSE)
上面的顶点结构表明它包含位置和颜色属性。
而第二种结构则要使用:
#define FVF_NORMAL_TEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
上面的顶点结构表明它包含了位置,法线向量,纹理坐标的属性(这些常量是D3D内置的)。
有一点要注意,你的标志的顺序必须要和你的顶点结构的顺序一一对应。如果想知道所有的D3DFVF标志,请查阅SDK文档。
2.1.2 三角形
三角形是构建3D物体的基本图形。为了构造物体,我们创建了三角形列表(triangle list)来描述物体的形状和轮廓。三角形列包含了我们将要画的每一个三角形的数据信息。例如为了构造一个矩形,我们把它分成两个三角形,如图2.4所示,最后指定每个三角形的顶点。
Vertex rect[6] = {v0, v1, v2, // 三角形0
v0, v2, v3}; // 三角形1
注意:指定三角形顶点的顺序是很重要的,将会按一定顺序环绕排列。
2.1.3 索引
3D物体中的三角形经常会有许多共用顶点。如图2.4所表示的矩形。虽然现在仅有两个点被重复使用,但是当要表现一个更精细更复杂的模型的时候,重复的顶点数将会变得很大。例如图2.5所示的立方体,仅有八个顶点,但是当用三角形列表示它的时候,所有的点都被重复使用。
为了解决这个问题,我们引入索引(indices)这个概念。它的工作方式是:我们创建一个顶点列表和一个索引列表(index list)。顶点列表包含所有不重复的顶点,索引列中则用顶点列中定义的值来表示每一个三角形的构造方式。回到那个矩形的示例上来,它的顶点列表的构造方式如下:
Vertex vertexList[4] = {v0, v1, v2, v3};
索引列表则定义顶点列中的顶点是如何构造这两个三角形的:
WORD indexList[6] = {0, 1, 2, //三角形0
0, 2, 3}; //三角形1
也就是说,用顶点列表中的0(vertexList[0])、1(vertexList[1])和2(vertexList[2])顶点构成三角形0;用顶点列表中的0(vertexList[0])、2(vertexList[2])和3(vertexList[3])顶点构成三角形1。
2.2虚拟照相机
照相机确定3D世界中的哪部分是可见的,因而需要将哪部分转换为2D图形。在3D世界中照相机被放置和定向,并且定义其可视体,图2.6展示了我们的照相机模型。
可视体是由可视角度和前裁剪面(Near Plane)与后裁剪面(Far Plane)定义的一个平截头体。之所以要选择平截头体构造可视体,是因为我们的显示器都是矩形的。在可视体中不能被看见的物体都会被删除,删除这种数据的过程就叫做“裁剪”。
投影窗口(Projection Window)是可视体内的3D几何图形投影生成的用来显示3D场景的2D图像的2D区域。重要的是要知道,我们使用min=(-1,-1)和max=(1,1)来定义投影窗口的大小。
为了简化绘制,我们使前裁剪面与投影窗口在同一平面上。并且,注意Direct3D中定义的投影平面(即投影窗口所在的平面)是Z = 1的平面。