绘制流水线的功能是,在给定3D场景和指定观察方向的虚拟摄像机的几何描述时,创建2D图像。
1.模型表示
1.1场景是物体或模型的集合,任何物体都可以用三角形网格逼近表示。在Direct3D中,顶点除了包含空间信息外,还有其他属性(如颜色,法线等等)。Direct3D赋予了我们定义顶点格式的自由。
(1)首先创建顶点数据的结构体;(2)然后用灵活顶点格式(FVF)的组合来描述顶点的结构。【灵活顶点描述中的顺序必须和顶点数据的结构体中顺序一致】
struct Vertex {
Vertex();
Vertex(float x,float y,float z)
{
_x=x;_y=y;_z=z;
}
float _x,_y,_z;
staticconst DWORD FVF;
};
const DWORD Vertex::FVF =D3DFVF_XYZ;
1.2三角形图元和索引
顶点列表: Vertex v[4]={v0,v1,v2,v3};
顶点索引的组织方式: WORD index[6]={0,1,2,0,2,3}; 这样构成两个三角形单元。
2. 虚拟摄像机
摄像机指定了场景对观察者的可见部分。投影窗口是一个2D区域,矩形投影窗口在X,Y方向坐标的最小值是(-1,-1),最大值(1,1)。Direct3D将投影平面定义为平面Z=1。
3.绘制流水线
大致步骤:局部坐标系->世界坐标系->观察坐标系->背面消隐->光照->裁减->投影->视口坐标系->光栅化。
坐标变换是借助矩阵来实现的,使用IDirect3DDevice9->SetTransform(D3DTRANSFORMSTATETYPEState,CONST D3DMATRIX*pMatrix)方法。//参数一描述变换类型;参数二描述变换矩阵。
3.1局部坐标系,用于定义构成物体的三角形单元列表的坐标系。在构建模型时无需考虑位置,大小或相对其他物体朝向等信息。
3.2世界坐标系,每个物体都处于自身的局部坐标系中,我们要将各种物体组织在一起,构成世界坐标系(全局坐标系)。在此处的变换包括平移,旋转,比例缩放等。
D3DXMATRIX cubeMattix;
D3DXMatrixTranslation(&cubeMattix,3,3,3);
Device-> SetTransform(D3DTS_WORLD,& cubeMattix);
3.3观察坐标系。我们将摄像机变换至世界坐标系的原点,将其旋转,使摄像机的光轴与世界坐标系的Z轴一致。同时世界坐标系中的物体都随着摄像机一同变换,保持摄像机的视场恒定。我们称变换后的物体位于观察坐标系中。
取景变换矩阵用函数D3DXMATRIX * D3DXMatrixLookAtLH(
D3DXMATRIX * pOut,
CONST D3DXVECTOR3 * pEye, //指定摄像机在世界坐标系中的位置
CONST D3DXVECTOR3 * pAt, //指定了世界坐标系的被观察点
CONST D3DXVECTOR3 * pUp // 世界坐标系中表示“向上”方向的向量
);
假定摄像机位于点(5,3,-2),观察点为世界坐标系的原点。我们可以这么创建取景变换矩阵:
D3DXVECTOR3 position(5.0f,3.0f,-2.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->SetTransform(D3DTS_VIEW,&v);
3.4背面消隐。默认情况下Direct3D认为顶点排列顺序为顺时针的三角形单元是正面朝向的,逆时针排列的三角形单元是背面朝向的。【在观察坐标系中】
若默认的消隐方式不能满足要求,我们可以通过修改绘制状态(D3DRS_CULLMODE)来达到目的
Device->SetRenderState(D3DRS_CULLMODE,value);
Value取值可为:
D3DCULL_NONE 完全禁用背面消隐;
D3DCULL_CW 只对顺时针的三角形单元进行消隐;
D3DCULL_CCW 默认值,只对逆时针的三角形单元进行消隐。
3.5光照。光源是在世界坐标系中定义的,但必须经取景变换至观察坐标系才可使用。
3.6裁减。一个三角形单元与视域体的关系有三种:完全在内部(保留);完全在外部(剔除);部分在内部分在外(部分保留,部分剔除)。
3.7投影。投影变换定义了视域体,并负责将视域体中的几何体投影到投影窗口。以下函数功能是根据视域体的描述信息创建投影矩阵。
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);
3.8视口变换。视口变换的任务是将顶点坐标从投影窗口转换到屏幕的一个矩形区域。
视口用D3DVIEWPOINT9来表示:
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,480,640,0,1};
Device->SetViewport(&vp);
3.9光栅化。光栅化的任务是绘制每个三角形单元。光栅化的最终结果是一幅显示在桌面上的2D图像。