DirectX之三——渲染管线与坐标系(Direct3D9)
Direct3D渲染管线
使用Direct3D绘制模型是需要经过一个流程的,这个流程就被称为渲染管线或绘制流水线,渲染管线可分为下列几个流程:
另外需要注意的是:Direct3D采用的是左手坐标系,如下图所示:
局部坐标系
局部坐标就是表示单个模型所需要的坐标,一般以模型的中心来作为局部坐标系的原点。而模型一般存储的是模型的顶点,不过顶点格式有的有法线,有的有纹理左边,Direct3D使用灵活顶点格式来表示顶点,如:
struct Vertex
{
Vertex(){}
Vertex(float x, float y, float z){
_x = x; _y = y; _z = z;
}
float _x, _y, _z;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ;
- 这里只使用了顶点,FVF代表顶点的表示形式,具体可选参数可参考MSDN
世界坐标系
世界坐标实际就是模型在世界坐标系中的位置,在有多个模型的情况下,必须要有一个统一的坐标系才能表示各模型之间的相对位置,这个坐标系就是世界坐标系。局部坐标转化为世界坐标可通过一下函数完成:
D3DXMATRIX worldMatrix;
D3DXMatrixTranslation(&worldMatrix, 1.0f, 0.0f, 0.0f);
Device->SetTransform(D3DTS_WORLD, &worldMatrix);
- 这里
worldMarix
是一个D3DXMATRIX
类型的矩阵对象。D3DXMatrixTranslation
是平移变换函数,类似的还有旋转函数、缩放函数,这里给个列表:
D3DXMATRIX *D3DXMatrixRotationX(D3DXMATRIX* pOut, FLOAT Angle);
D3DXMATRIX *D3DXMatrixRotationY(D3DXMATRIX* pOut, FLOAT Angle);
D3DXMATRIX *D3DXMatrixRotationZ(D3DXMATRIX* pOut, FLOAT Angle);
D3DXMATRIX *D3DXMatrixScaling( D3DXMATRIX* pOut, FLOAT sx, FLOAT sy, FLOAT sz);
观察坐标系
观察坐标系可以说是指以相机为原点的世界坐标系,其实就是将相机变换到世界原点处,并朝向Z轴正方向。因为我们最终看到的图像都是透过相机来计算的,所以将相机至于原点便于后续计算。设置过程如下:
D3DXVECTOR3 position( 0.0f, 0.0f, -5.0f );
D3DXVECTOR3 target( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f );
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
Device->SetTransform(D3DTS_VIEW, &V);
背面消隐
由于一个多边形有两个侧面,一个称之为正面,一个称之为背面,背面消隐就是消除背面朝向相机的多边形。默认状态下,Direct3D认为顶点顺时针排列的多边形为正面朝向相机(观察坐标系)。可以通过Device->SetRenderState(D3DRS_CULLMODE, Value);
来控制背面消隐。Value取值如下:
- DDCULL_NONE 禁用背面消隐;
- DDCULL_CW 只对顺时针绕序的三角形进行消隐;
- D3DCULL_CCW 默认值,只对逆时针绕序的三角形进行消隐;
光照跟裁剪
光照就是根据光源来计算表面颜色,详细的先不谈了。相机模拟的是人眼,只能看到一个锥形范围内的物体,这个锥成为视角锥,而裁剪就是将相机所不能看到的物体裁剪掉。
投影
投影就是将视角锥内物体坐标转化为二维平面上的坐标;过程如下:
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, float(screenWidth) / screenHeight, 1.0f, 1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
- 变换后得到的坐标(x,y)的范围为(-1~1,-1~1),此过程还能得到深度缓存,实际就是z缓存,其范围为(0~1)。
视口变换
视口变换就是将投影过后的二维左边转化为屏幕上的实际坐标。这里的屏幕坐标是指相对于当前窗口的像素坐标。过程如下:
D3DVIEWPORT9 vp = {0, 0, screenWidth, screenHeight, 0, 1};
Device->SetViewport(&vp);
- 最后的参数0,1是深度的限制范围,0~1表示将视锥体内的所有物体都显示出来。
光栅化
所谓的光栅化就是将一个多边形光栅化为一个一个像素,只有这样才能将屏幕上的像素争取着色。这一步只需了解即可。
注意!!!
这里列一些细节上容易出错的地方:
- Direct3D是以[1,4]或[1,3]的行向量来存储点坐标的,这意味着,顶点变换是通过行向量变换矩阵来完成的。假如有两个变换矩阵,按照先后的顺序,应该是preMatrix nextMatrix;
- 视口坐标系中,是以窗口的左上角为原点(0,0),横轴为x轴,向右为正;纵轴为y轴,向下为正;
- 假如有顶点格式中使用了纹理坐标,则纹理的左上角为原点(0,0),右下角(1,1),横轴为x轴,纵轴为y轴。