渲染流水线
对于Direct3D,上述过程通常被认为是一个渲染流水线。
未经转换和照明的顶点从一端进入,在内部这些顶点将完成几个连续操作。然后,经过转换和照明处理的顶点从另一端出来。
渲染流水线的大部分过程都是在进行坐标转换 ,将顶点从一个坐标系转换到别的坐标系。
在使用Direct3D来进行转换时,用户只需要提供描述系统转换的完整转换矩阵,通过IDirect3DDevice->SetTransform方法来实现相应的变换。
HRESULT SetTransform(
D3DTRANSFORMSTATETYPE State, //变换的类型
CONST D3DMATRIX *pMatrix //进行变换的变换矩阵);
世界变换
渲染流水线的第一步是将物体从本地坐标系转换到世界空间,这一过程称为世界变换。
它的作用是: 把独立的物体放在一个统一的坐标系内,组合成一个完整的场景。在世界变换中主要完成的是对模型的转换,包括旋转、缩放、*移等。
设置世界变换的函数如下:
g_pD3Ddevice->SetTransform(
D3DTS_WORLD, &matWorld);
g_pD3DDevice为有效的Direct3D设备指针
matWorld代表一个变换矩阵。
视图变换
把物体转换到世界空间后,接下来就需要确定视图空间,这个过程称为视图变换。
首先我们需要确定虚拟摄像机的属性。在Direct3D中,关于虚拟摄像机的属性主要包括:摄像机位置、摄像机的朝向和摄像机的正方向,分别用向量表示。可以从以下函数生成视图变换的矩阵。
D3DXMATRIX *D3DXMatrixLookAtLH(
D3DXMATRIX *pOut, //输出用于视图变换的矩阵
CONST D3DXVECTOR3 *pEye, //摄像机的位置
CONST D3DXVECTOR3 *pAt, //摄像机朝向的位置
CONST D3DXVECTOR3 *pUp //摄像机的正方向
);
接下来,使用下面的函数来设置视图变换。
g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
g_pD3DDevice为有效的Direct3D设备指针
matWorld代表一个视图变换矩阵
投影变换
把摄像机观察到的三维景像显示在二维的*面上,这种三维到二维的变换就是投影变换。实际应用中,主要的投影变换有两种类型:
Ø正交投影
Ø 透视投影
1. 正交投影
在正交投影中,投影向量与观察*面垂直,物体坐标沿观察坐标系的z轴*行投影到观察*面上,观察点和观察*面的距离不影响物体的大小。
可以使用下面的函数来得到正交投影的变换矩阵:
D3DXMATRIX *D3DXMatrixOrthoLH(
D3DXMATRIX *pOut, //输出用于正交投影的变换矩阵
FLOAT w, //取景体宽度
FLOAT h, //取景体高度
FLOAT zn, //取景体离摄像机的最*距离
FLOAT zf //取景体离摄像机的最远距离
);
2. 透视投影
透视投影的特点:是越远的物体在投影*面上的成像越小,这样生成的投影图更加具有纵深感。
透视投影的观察范围是一个*截台体。*截台体是指一个去除了尖头的锥体。在计算机图形学中,观察*截面的概念是,锥体的尖头位于虚拟摄像机的位置,而摄像机指向该锥体的底部,将锥体的四个侧面向屏幕的四边投影,并切除远*裁剪*面位置的锥体的前后部分。得到的观察*截面代表摄影空间在渲染场景中的可见部分。实际应用中,如果我们要实现一个三维的场景,则我们通常使用透视投影。
下面的函数用于定义透视变换的矩阵:
D3DXMATRIX *D3DXMatrixPerspectiveFovLH(
D3DXMATRIX *pOut, //输出用于透视投影的变换矩阵
FLOAT fovY, //摄像机镜头的夹角(在y轴上的成像角度)
FLOAT Aspect, //*截台体的纵横比
FLOAT zn, //**截面的距离
FLOAT zf //远*截面的距离
);
顶点从均匀转化为非均匀:
Ø在顶点坐标信息里除顶点位置信息外再加一个W分量坐标,设定其初始值为1.0。
Ø在顶点通过T&L流水线中的多个矩阵传送时,w坐标将改变它的值。w值不为1.0的顶点是均匀的。当转换换结束时,就需要把顶点恢复为不均匀的形式,这是通过x、y和z坐标除以w完成的。w坐标的倒数也被存储起来。这个过程非常必要,因为光栅处理程序需要得到以非均匀x、y和z坐标以及均匀w的倒数值(reciprocal-of-homogeneous-w, RHW)表示的顶点。
视口变换
空间变换的最后一步是通过定义屏幕显示区域的实际宽、高等参数,将顶点从投影坐标转换为最终显示的以像素为单位的屏幕坐标。
在Direct3D中定义的视口结构:
typedef struct _D3DVIEWPORT9 {
DWORD X; //视口区域的左上角x坐标
DWORD Y; //视口区域的左上角y坐标
DWORD Width; //视口区域的宽度
DWORD Height; //视口区域的高度
float MinZ; //视口内景物的最小深度值,0-1.0之间,通常为0
float MaxZ; //视口内景物的最大深度值,0-1.0之间,通常为1
} D3DVIEWPORT9;
通常情况下,参数MinZ和MaxZ被设为0和1.0f,即取景范围的最*和最远距离,表示在投影取景范围内,顶点只要满足了x∈(-1.0f , 1.0f)、y∈(-1.0f , 1.0f)和z∈(0.0f , 1.0f),就能通过裁剪,予以显示。
SetViewport()相当于把投影空间的顶点P(x,y,z)乘以以下变换矩阵:
经过转换后,顶点P的屏幕二维坐标x’,y’为:
x, = x × Width/2 + X + Width/2
y, = y × Height/2 + Y + Height/2
z’值为:
z, = z × (MaxZ - MinZ) + MinZ
光栅化
经过视口变换,我们获得了一系列2D三角形。光栅化阶段被用于在描绘三角形时,计算每个像素的颜色值。
光栅化过程需要进行大量计算,并通常由特定的图像硬件来完成。光栅化的结果时一个2D图像,将被显示在屏幕上。