固定功能流水线
Microsoft® Direct3D®中把几何体送经固定功能几何流水线进行处理的那部分是变换引擎。它取得三维模型和观察者在世界空间中的位置,把顶点投影到屏幕上,并根据视区对顶点进行裁剪。变换引擎也对每个顶点执行光照计算,得到漫反射色和镜面反射色。
Microsoft® Direct3D®中把几何体送经固定功能几何流水线进行处理的那部分是变换引擎。它取得三维模型和观察者在世界空间中的位置,把顶点投影到屏幕上,并根据视区对顶点进行裁剪。变换引擎也对每个顶点执行光照计算,得到漫反射色和镜面反射色。
几何流水线接收顶点作为输入。变换引擎将三个变换——世界、观察和投影变换——应用于顶点,对结果进行裁剪,将所有数据传递给光栅化器。下图描绘了这些步骤的顺序。

在流水线的开始处,没有进行任何变换,因此所有建模的顶点是相对于局部坐标系——这是一个局部原点和方向——声明的。这个坐标系通常被称为建模空间,单个的坐标被称为建模坐标。
几何流水线的第一步将建模顶点从局部坐标系变换到场景中所有物体都使用的一个坐标系。重定位顶点的过程被称为世界变换。新的坐标系通常被称为世界空间,世界空间中的顶点用世界坐标表示。
下一步,描述三维世界的顶点根据摄像机进行重定位。也就是说,应用程序在场景中选择一个视点,世界空间中的坐标被重定位并围绕摄像机的视线旋转,从世界空间转变到摄像机空间。这就是视变换。
下一步是投影变换。在流水线的这一部分,为了营造场景的立体感,通常要根据物体与观察者之间的距离对它们进行缩放,使得近的物体显得比远处的物体大一些,等等。为了简单,本文档将经过变换的顶点所在的空间称为投影空间。一些图形学书籍可能将投影空间称为后透视齐次空间(post-perspective homogeneous space)。并不是所有的投影变换都会对场景中物体的大小进行缩放,这样的投影有时被称为仿射或正交投影。
在流水线的最后一部分,任何在场景中不可见的顶点被移除,这样光栅化器就不必花时间去为一些不可见的东西计算颜色及进行明暗处理,这个过程被称为裁剪。经过裁剪后,剩下的顶点根据视区的参数进行缩放并转换到屏幕坐标。最后得到的顶点——在屏幕上看见的经过光栅化的场景——存在于屏幕空间中。
为了使用传统的弹性顶点格式(FVF)的格式,应该在调用IDirect3DDevice9::SetFVF方法时用一个FVF码作为参数,如以下示例代码所示。
g_d3dDevice->SetFVF( CUSTOM_FVF );
以下主题涵盖了传统FVF格式的类型。
本主题说明了初始化并使用包含位置、法向和纹理坐标的顶点所需的步骤。
第一步是定义一个自定义顶点类型和FVF码,如以下示例代码所示。
struct Vertex
{
FLOAT x, y, z;
FLOAT nx, ny, nz;
FLOAT tu, tv;
};
const DWORD VertexFVF = ( D3DFVF_XYZ | D3DFVF_NORMAL
| D3DFVF_TEX1 );
下一步通过调用IDirect3DDevice9::CreateVertexBuffer方法创建一个有足够空间包含四个顶点的顶点缓存,如以下示例代码所示。
g_d3dDevice->CreateVertexBuffer(
4*sizeof(Vertex), VertexFVF,
D3DUSAGE_WRITEONLY,
D3DPOOL_DEFAULT, &pBigSquareVB);
下一步是设置每个顶点的值,如以下示例代码所示。
Vertex * v;pBigSquareVB->Lock( 0, 0, (BYTE**)&v, 0 ); v[0].x = 0.0f; v[0].y = 10.0; v[0].z = 10.0f;v[0].nx = 0.0f; v[0].ny = 1.0f; v[0].nz = 0.0f;v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].x = 0.0f; v[1].y = 0.0f; v[1].z = 10.0f;v[1].nx = 0.0f; v[1].ny = 1.0f; v[1].nz = 0.0f;v[1].tu = 0.0f; v[1].tv = 0.0f; v[2].x = 10.0f; v[2].y = 10.0f; v[2].z = 10.0f;v[2].nx = 0.0f; v[2].ny = 1.0f; v[2].nz = 0.0f;v[2].tu = 0.0f; v[2].tv = 0.0f; v[3].x = 0.0f; v[3].y = 10.0f; v[3].z = 10.0f;v[3].nx = 0.0f; v[3].ny = 1.0f; v[3].nz = 0.0f;v[3].tu = 0.0f; v[3].tv = 0.0f; pBigSquareVB->Unlock();
至此顶点缓存已经初始化结束,可以准备渲染了。以下示例代码显示了如何使用传统的弹性顶点格式(FVF)绘制一个正方形。
g_d3dDevice->SetFVF( VertexFVF );
g_d3dDevice->SetStreamSource( 0, pBigSquareVB,
4*sizeof(Vertex) );
g_d3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,
0 ,2);
把一个FVF传递给IDirect3DDevice9::SetFVF会指定一个传统的FVF,顶点数据在数据流0中。
本主题说明了初始化并使用包含位置、漫反射色、镜面反射色和纹理坐标的顶点所需的步骤。
第一步是定义自定义顶点类型和弹性顶点格式(FVF),如以下示例代码所示。
struct LVertex
{
FLOAT x, y, z;
D3DCOLOR specular, diffuse;
FLOAT tu, tv;
};
const DWORD VertexFVF = (D3DFVF_XYZ | D3DFVF_DIFFUSE
|
D3DFVF_SPECULAR | D3DFVF_TEX1 );
下一步通过调用IDirect3DDevice9::CreateVertexBuffer创建一个有足够空间包含四个顶点的顶点缓存,如以下示例代码所示。
g_d3dDevice->CreateVertexBuffer(
4*sizeof(LVertex), VertexFVF,
D3DUSAGE_WRITEONLY, D3DPOOL_DEFAULT, &pBigSquareVB);
下一步是设置每个顶点的值,如以下示例代码所示。
LVertex * v;pBigSquareVB->Lock( 0, 0, (BYTE**)&v, 0 ); v[0].x = 0.0f; v[0].y = 10.0; v[0].z = 10.0f;v[0].diffuse = 0xffff0000;v[0].specular = 0xff00ff00;v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].x = 0.0f; v[1].y = 0.0f; v[1].z = 10.0f;v[1].diffuse = 0xff00ff00;v[1].specular = 0xff00ffff;v[1].tu = 0.0f; v[1].tv = 0.0f; v[2].x = 10.0f; v[2].y = 10.0f; v[2].z = 10.0f;v[2].diffuse = 0xffff00ff;v[2].specular = 0xff000000;v[2].tu = 0.0f; v[2].tv = 0.0f; v[3].x = 0.0f; v[3].y = 10.0f; v[3].z = 10.0f;v[3].diffuse = 0xffffff00;v[3].specular = 0xffff0000;v[3].tu = 0.0f; v[3].tv = 0.0f; pBigSquareVB->Unlock();
至此顶点缓存已经初始化完成,可以准备渲染了。以下示例代码显示了如何使用传统FVF绘制一个正方形。
g_d3dDevice->SetFVF( VertexFVF );
g_d3dDevice->SetStreamSource( 0, pBigSquareVB,
4*sizeof(LVertex) );
g_d3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,
0 ,2);
把一个FVF传递给IDirect3DDevice9::SetFVF方法会指定一个传统FVF,并且数据流0是唯一有效的数据流。
本主题说明了初始化并使用包含经过变换的位置、漫反射色、镜面反射色和纹理坐标的顶点所需的步骤。
第一步是定义自定义顶点类型和弹性顶点格式(FVF),如以下示例代码所示。
struct TLVertex
{
FLOAT x, y, z,
rhw;
D3DCOLOR specular, diffuse;
FLOAT tu, tv;
};
const DWORD VertexFVF = (D3DFVF_XYZRHW |
D3DFVF_DIFFUSE |
D3DFVF_SPECULAR | D3DFVF_TEX1 );
下一步通过调用IDirect3DDevice9::CreateVertexBuffer方法创建一个有足够空间包含四个顶点的顶点缓存,如以下示例代码所示。
g_d3dDevice->CreateVertexBuffer(
4*sizeof(TLVertex), VertexFVF,
D3DUSAGE_WRITEONLY, D3DPOOL_DEFAULT, &pBigSquareVB);
下一步设置每个顶点的值,如以下示例代码所示。
TLVertex * v;pBigSquareVB->Lock( 0, 0, (BYTE**)&v, 0 ); v[0].x = 0.0f; v[0].y = 10.0; v[0].z = 10.0f; v[0].rhw = 1.0f;v[0].diffuse = 0xffff0000;v[0].specular = 0xff00ff00;v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].x = 0.0f; v[1].y = 0.0f; v[1].z = 10.0f; v[1].rhw = 1.0f;v[1].diffuse = 0xff00ff00;v[1].specular = 0xff00ffff;v[1].tu = 0.0f; v[1].tv = 0.0f; v[2].x = 10.0f; v[2].y = 10.0f; v[2].z = 10.0f; v[2].rhw = 1.0f;v[2].diffuse = 0xffff00ff;v[2].specular = 0xff000000;v[2].tu = 0.0f; v[2].tv = 0.0f; v[3].x = 0.0f; v[3].y = 10.0f; v[3].z = 10.0f; v[3].rhw = 1.0f;v[3].diffuse = 0xffffff00;v[3].specular = 0xffff0000;v[3].tu = 0.0f; v[3].tv = 0.0f; pBigSquareVB->Unlock();
至此顶点缓存已经初始化完成,可以准备渲染了。以下示例代码显示了如何使用传统FVF绘制一个正方形。
g_d3dDevice->SetFVF( VertexFVF );
g_d3dDevice->SetStreamSource( 0, pBigSquareVB,
4*sizeof(TLVertex) );
g_d3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,
0 ,2);
把一个FVF传递给IDirect3DDevice9::SetFVF会指定一个传统的FVF,顶点数据在数据流0中。