DIRECTX9.0绘制流水线
主要目的是:
在给定的3D场景和指定观察方向的虚拟摄像机(virtual camera)的几何描述时,创建一幅2D图像
一.模型表示:
三角形网格是构建物体模型的基本单元.
1.顶点格式:
顶点除了包含空间信息外,还可以包含其他的附加属性
顶点格式可以自己进行定义,这样的灵活顶点格式(Flexible vertexFormat, FVF)可用D3DFVF来进行描述我们自己定义的顶点格式.
例如:
#define FVF_NORMAL_TEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
struct NormalTexVertex
{
float _x, _y, _z;
float _nx, _ny, _nz;
float _u, _v;
}
以上定义的含义是对应于该顶点格式的顶点结构,包含了位置,法线以及纹理坐标等属性.
定义灵活顶点格式时必须遵循的一个约定是:灵活顶点格式标记的指定顺序必须与顶点结构中相应类型数据定义的顺序保持一致.
2.三角形单元
三角形单元是3D物体的基本组成部分
绕序(winding order)
顺时针为正面
3.索引
构成一个3d物休的众多三角形单元之间会共享许多公共顶点,为解决该问题引入了索引(indices).
我们创建一个顶点列表(vertex list)和一个索引列表(index list).
顶点列表包含了全部独立顶点,索引列表包含了指向顶点列表的索引,这些索引规定了为构建三角形单元,各顶点应按何种方式来组织.
二.虚拟摄像机:
摄像机指定了场景对观察者的可见部分,即我们将依据哪部分3D场景来创建2D图像.在世界坐标系中,摄像机有一定的位置和方向,定义了可见的空间体积(volume of space).
摄像机的视角空间是一个平截头体(frustum),在3d图形学中也可称为视域体或视截体.
投影窗口(projection window)是一个2D区域,是由3d几何体通过投影映射而得.很重要的一点是,矩形投影窗口在x和y方向坐标的最小值是min=(-1, -1),最大值是max=(1,1)
为简化绘制工作,我们将近裁剪面和投影平面合二为一.注意,direct3d将投影平面定义为平面z=1;
三.绘制流水线:
应用一个变换矩阵的方法是使用IDirect3DDevice9->SetTransform方法
1.局部坐标系
局部坐标系local space或建模坐标系modeling space是用于定义构成物体的三解形单元列表的坐标系.
2.世界坐标系
构建各种物体模型时,每个模型都位于其自身的局部坐标系中.我们还需要将这些物体组织在一起构成世界坐标系(全局坐标系)中的场景.位于局部坐标系中的物体通过一个称为世界变换world transform 的运算变换到世界坐标系中,该变换通常包括平衡,旋转以及比例运算,分别用于设定该物体在世界坐标系中的位置,方向以及模型的大小.
世界变换用一个矩阵来表示:
Device->SetTransform(D3DTS_WORLD, 变换矩阵)
3.观察坐标系
摄像机放在原点,让光轴与世界坐标系z轴正方向一致,同时,世界空间中的所有几何体都有随着摄像机一同进行变换,以保证摄像机的视场恒定.这种变换称为取景变换view space transformation, 我们称变换后的几何体位于观察坐标系view space 中
取景变换矩阵可由
//建立一个左手观察坐标系
D3DXMATRIX * D3DXMatrixLookAtLH(
D3DXMATRIX *pOut,
CONST D3DXVECTOR3 *pEye, //摄像机在世界坐标系中的位置
CONST D3DXVECTOR3 *pAt, //指定世界坐标系中被观察点
CONST D3DXVECTOR3 *pUp //向上的方向向量
);
例:
D3DXVECTOR3 position(5.0f, 3.0f, –10.0f);
D3DXVECTOR3 targetPoint(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 worldUp(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &targetPoint, &worldUp);
Device->SetTarnsform(D3DTS_VIEW, &v); //取景变换需要用此方法来设定
4.背面消隐
每个多边形都有两个侧面,我们将其中一个侧面标记为正面,另一个侧面标记为背面,正面朝向多边形评功遮挡了位于其背面朝向的多边形,Direct3D正是利用了这一点而将背面朝向多边形加以剔除,这称为消隐
为了实现背面消隐,Direct3D需要区分哪能引动多边形是下面朝向的,哪些是朝向的,聊胜于无状态下.Direct3D认为顶点排列顺序为顺时针的三角形单元是下面朝向的,顶点排列顺序为逆时针的三角形单元是背面朝向的.
如果由于某些原因的消隐方式不能满足应用的要求,我们可以通过修改绘制状态来达到目的.
HRESULT SetRenderState(
D3DRENDERSTATETYPE State, //要改变的参数
DWORD Value //改变的值
);
State=D3DRS_CULLMODE
VALUE:
D3DCULL_NONE 完全禁用背面消隐。
D3DCULL_CW 只对顺时针绕序的三角形单元进行消隐。
D3DCULL_CCW 默认值,只对逆时针绕序的三角形单元进行消隐。
5.光照
光源是在世界坐标系中定义的,但必须经取景变换至观察坐标系方可使用.
6.裁剪
现在我们想将那些位于视域体外的几何体剔除掉,这个过程称为裁剪.
7.投影:
观察坐标系中,我们的任务是获取3D场景的2D表示,从n维变换为n-1维的过程称为投影projection.
我们只处理透视投影perspective projection透视投影会产生"透视缩短"foreshortening的视觉效果,即近大远小这类投影使得我们可以用2D图像表示3D场景.
投影变换定义了视域体,并负责将视域体中的几何体投影到投影窗口中
//依据视域体的描述信息创建一个投影矩阵
D3DXMATRIX * D3DXMatrixPerspectiveFovLH(
D3DXMATRIX *pOut,
FLOAT fovy, //角度
FLOAT Aspect, //长高比
FLOAT zn, //到最近平面的距离
FLOAT zf //到最远平面的距离
);
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, PI * 0.5f, (float)width/(float)height, 1.0f, 1000.0f);
Device->SetTransform(D3DTS_PROJECTION. &proj);
8.视口变换
视口变换viewport transform的任务是将顶点坐标从投影窗口转换到屏幕的一个矩形区域中,该矩形区域称为视口viewport.
矩形的视口是相对于窗口来描述的,因为祸患总是处于窗口内部并且其位置要用窗口坐标来指定
typedef struct D3DVIEWPORT9 {
DWORD X;
DWORD Y;
DWORD Width;
DWORD Height; //前4个数据成员定义了视口矩形相对对于其父窗口的位置及大小
float MinZ; //深度缓存中的最小深度值
float MaxZ; //最大深度值[0,1]
} D3DVIEWPORT9, *LPD3DVIEWPORT9;
一旦我们填充好D3DVIEWPORT9结构,就可这样来设置视口:
D3DVIEWPORT9 vp = {0, 0, 640, 480, 0, 1};
Device->SetViewport(& vp);
9.光栅化:
为了绘制每个三角形单元,如何计算构成三角形单元的每个像素的颜色值