使用微软的D3D来编程需要熟悉3D几何原理。本节介绍建立3D世界的最重要的几何概念。
1.1.1. 3-D坐标系统
典型的3D图形程序使用两种笛卡儿坐标系统:左手和右手。两个坐标系统中,正X轴指向右边,正Y轴指向上。你可以通过你左右手指间指向与正X轴相同时大拇指指向的方向来记住坐标方向。下图描述了这两种系统。
微软的D3D使用左手系统,如果你正在将一个基于右手坐标系统的程序导入到程序中,你必须做两个改变过度到D3D。
1.1.2. 3-D原基(点阵)
一个3D原基就是一个形成单个3D实体的顶点集合。最简单的原基是3D系统中点的集合,也叫做点列表。
当然,3D原基是多边形。一个多边形是一个至少包括3个顶点的封闭的图形。最简单的多边形是3角形。微软D3D使用三角形来组成大多数的多边形,因为三角形中的三个顶点是共面的,渲染不是平面的顶点是无效的。你可以通过合并三角形来形成大的、复杂的多边形和网格。
下图描述了一个立方体。正方体的每个面由2个三角形组成,所有三角形形成一个正方体原始。你能使用材质和原料到原始的每个面上来使他们看起来象一个固体形状。
你也可以用三角形来建立表面平滑的平面。下面的图显示了一个使用三角形来仿真的球体;在应用材料以后,在渲染的时候球体看起来平滑很多。如果你使用Gouraud阴影,更是这样。详细的细节参见Gouraud 阴影。
1.1.3. 面和顶点法线向量
网格中的每个面都有一个正交的法线向量。向量的方向是由顶点定义的顺序和左右手坐标系统。正面法线从正面的前边指出。微软的D3D系统,仅仅正面的前边是可见的,前面就是顶点以顺时针方向定义的面。
D3D使用顶点法线来表示阴影、光线和材质效果。
在一个多边形上应用阴影时,D3D使用顶点法线来计算光源和表面之间的角度。其为顶点计算色彩和亮度值,并且通过所有原始表面来为每个顶点加入。D3D通过角度来计算光亮度值。角度越大,亮度越小。
如果你正在一个平面上创建一个对象,设置顶点法线来指向表面的垂线,就如下图所示。定义一个由两个三角形组成的平面。
然而,很可能你的对象有一些不共面条的三角形组成;为了获得通过所有三角形带的平滑阴影,一个简单的办法就是首先计算与顶点相关的每个多边形曲面法线矢量。顶点法线被设置为对于每个曲面法线有相同的角度。但这个方法在复杂的初基(点阵)并不是特别有效。
上面的方法通过下图来描述,他展示了两个曲面,S1和S2有一条边相交。S1和S2的法线使用蓝色表示。顶点法线矢量用红色显示。顶点法线矢量和S1和S2面上的曲面法线角度一样。当这两个表面被点亮或使用Gouraud阴影,结果在他们之间是一个平滑的阴影,平滑的圆形边。
如果顶点发现朝其中关联的一个面倾斜,它导致指向表面的光强度增加或降低,主要依赖于和光源之间的角度。下面表明这个例子。同样,这些面是边相交的,顶点法线向S1倾斜导致其和光源之间角度较小。
你可以使用Gouraud阴影来在3D场景中显示一些带有明显边的对象,为了这么做,需要在每个明显边缘的面相交处复制顶点法线矢量,如下图显示:
如果你使用DrawPrimitive方法来粉刷你的场景,定义带有明显边界的对象作为一个三角形列表而不是三角形带。当你定义一个作为三角形带的对象,D3D将其作为一个由多个三角形面组成的单个多边形。Gouraud阴影应用到通过多边形每个面以及相邻面之间;结果是具有从一个面到另一个面平滑阴影的对象;因为一个三角形列是一系列分解三角形面组成的一个多边形,D3D使用Gouraud阴影贯穿多边形的每个面;然而,它并不应用到面到面,如果两个或多个三角形列中的三角形相邻,在他们之间会有一个明显的边界。
另外在粉刷一个带有明显边界的对象时选择是将其作为平面阴影。这是最有效的方法,但他可能导致一个对象没有使用Gouraud阴影粉刷理想的效果。
1.1.4. 光栅化规则
经常,指定的顶点并不正好和屏幕上的像素相匹配;当这个发生的时候,D3D使用三角形光栅化原则来那些像素对应到给定的三角形上。
1. 三角形光栅化原则
2. 点和线规则
3. 点精灵规则
1.1.4.1.1. 三角形光栅化规则
D3D使用顶-左填充约定作为填充几何算法。这同微软GDI以及OpenGL的矩形填充约定相同。在D3D中,像素的中央是决定性点,如果中心在一个三角形中,那这个像素是三角形的一部分。像素中心是整数坐标。
这个D3D使用的三角形光栅化原则并不是必须应用到所有可用的硬件上;你的测试或许揭示这些规则小的变化。
下图显示一个左上角在(0,0)点的矩形,其右下角在(5,5)点;这个举行填充了25个像素,就像你预期的一样,矩形的宽度定义为右-左,高度是底减去顶部。
在顶左填充约定中,顶指的是水平跨度的垂直位置,左指的是一个像素宽度的水平位置。一个边不能是顶边,除非它是水平的;通常大多数三角形有唯一的左和右边。
顶-左填充约定决定了当一个三角形穿过一个像素中心时D3D的行为。下图展示了两个三角形,一个是(0,0),(5,0),(5,5);而另外一个在(0,5),(0,0),(5,5)。这个例子中第一个三角形得到15个像素(黑色显示),然而第二个得到10个像素(灰色显示),因为他们共享边是第一个三角形的左边边。
如果你定义一个矩形其左上角在(0.5,0.5),右下角在(2.5,4.5),中心点是(1.5,2.5)。当D3D光栅 tesselate这个矩形时,每个像素的中心都明显的在矩形的内部,且左上角填充规则不必要。下图说明这个内容;矩形中的像素依据D3D包括的三角形标记。
如果你移动上面例子中的矩形使其左上角坐标在(1.0,1.0),它的右下角在(3.0,5.0),它的中心点在(2.0,3.0),D3D使用左上填充约定;大多数三角形在两个或多个三角形的边界上,如下图所示:
两个矩形中,影响的相同像素如下:
1.1.4.1.2. 点和线规则
点和点精灵粉刷方式是相同的,他们都依照屏幕对齐的四边形方式粉刷,从而和多边形粉刷具有相同的规则。
Non-antialiased线粉刷方式同GDI相同。
更多关于antialiased线的粉刷,见ID3DXLine。
1.1.4.1.3. 精灵点规则
精灵点和补丁初基首先被镶嵌到三角形中,然后使用结果三角形光栅化原则来处理;更多的信息参见:精灵点。
1.1.5. 矩形
贯穿D3D和Windows编程,屏幕上的对象都归诸于范围矩形。矩形的边同屏幕的边平行,因此举行可以使用两个点来表示,左上角和右下角。大多数程序在blitting到屏幕上或执行hit检测的时候使用携带矩形信息的RECT结构。
在C++中,RECT结构定义如下:
typedef struct tagRECT {
LONG left; // This is the upper-left corner x-coordinate.
LONG top; // The upper-left corner y-coordinate.
LONG right; // The lower-right corner x-coordinate.
LONG bottom; // The lower-right corner y-coordinate.
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
前面的例子中,left和top成员指的是矩形左上角的x和y坐标,同样right和bottom指的是右下角的x和y的坐标。下图描述了你怎么形象化的理解这些值。
为了效率、一致性和容易使用的目的,所有D3D显示函数都使用矩形来工作。
1.1.6. 三角形Interpolants
在粉刷过程中,管道插入穿过每个三角形的顶点数据;顶点数据可以明显的变化并包含(但不限制于)弥漫的色彩、有金属光泽的色彩、弥漫的alpha(三角形通明性)、金属光泽alpha和雾化因素(为顶点管道降低金属光泽alpha以及降低可编程顶点管道雾化登记);这个顶点数据被定义为顶点声明。
对于许多顶点数据来说,插入独立于当前的阴影模式,如下表描述:
阴影模式 | 描述 |
平面 | 仅仅雾化因素被插入到平面阴影模式中;对于所有其他的插入,第一个顶点的颜色将应用为穿过整个面的色彩 |
Gouraud | 在所有三个顶点之间执行线性插入 |
弥漫色彩和金属光泽色彩不同对待,依赖于颜色模式。在RGB模式中,系统在插入中使用红、绿、蓝成分。
色彩的Alpha成分作为一个单独的interpolant对待,因为设备驱动可以用两种方法来实现通明性:使用材质混合或使用点画法。
使用D3DCAPS9结构体的ShadeCaps成员来决定当前设备驱动支持什么样的interpolation形式。
1.1.7. 矢量、顶点和四元数
贯穿D3D,顶点描述位置和方向;初基中的每个点被描述为一个具有位置、颜色、材质坐标和给定方向的法线向量的一个向量。
四元数添加一个元素到[x ,y ,z]值中来定义一个三分量矢量。四元数是3D旋转时使用的矩阵方法的另一个选择;一个四元数表达一个3D平面的轴以及绕轴旋转的度。例如:四元数可能表示一个(1,1,2)轴和一个1弧度的旋转。四元数携带重要的信息,但他们真正的作用来自两个你可以执行的操作:组合和插入(interpolation)。
在一个四元数上执行合成操作和合并他们很相似,两个四元数的合成标记为:
Q=q1Oq2
两个四元数的合成应用到几何学上意味着:绕轴2旋转几何图形旋度2,然后绕轴1旋转旋度1;这个例子中,Q表示一个绕一个轴的旋转角度,也是作用q2然后q1到几何图形上的结果。
使用四元数interpolation,程序可以从一个轴和方向计算到另一个的平滑的和合理的路径。因此,在q1和q2之间的interpolation为从严格方向到另一个方向提供了动画的简单方法。
当你一起使用组合和interpolation时候,他们为你以看起来很复杂的方式操作一个几何图形提供了一个简单的方法。例如,你想旋转一个图像到给定的方向,你知道绕轴2旋转r2角度,然后绕轴1旋转r1角度,但你不知道最终的四元数,通过使用组合,你能够合并两个旋转为一个单一的四元数,然后,你能够从原来的点到组合四元数interpolate来得到一个平滑的转换。
D3D扩展(D3DX)工具库包含使用四元数的函数,例如:D3DXQuaternionRatationAxis为一个向量添加一个旋转值,其返回一个D3DXQUATERNION结构体四元数结果。另外,D3DXQuaternionMultiply函数组合四元数,D3DXQuaternionSlerp在两个四元数之间执行球形线性interpolation。