顶点着色器
在Microsoft® DirectX® 8.x之前,Microsoft® Direct3D®以固定功能流水线的方式运作,把三维几何体渲染到屏幕上的像素。用户设置流水线的属性,以控制Direct3D变换、光照和渲染像素的方式。固定功能顶点格式用来确定输入顶点的格式,在编译时定义。一旦定义,用户就无法在运行的时候控制流水线的改变。
- 创建顶点着色器 – 本节包含的代码实例,用一个顶点着色器将一固定颜色应用于物体的顶点。本示例包含了对所使用的方法的详细描述。
- 顶点颜色 – 又一示例,显示了更多的代码实例,用来加入纹理,并把顶点颜色和纹理混合。
- 纹理 – 又一示例,显示了更多的代码实例,用来加入纹理,并把顶点颜色和纹理混合。
- 带光照的纹理贴图 - 又一示例,显示了更多的代码实例,用来加入纹理,并把顶点颜色和纹理混合。
- 将顶点着色器与顶点声明分离 – 现在顶点着色器声明与顶点声明已经分开。本节包含了固定功能流水线和顶点着色器流水线的声明之间的映射关系的详细资料。
通过允许在运行的时候进行变换、光照和渲染的功能,可编程着色器将图形流水线带入了一个新的高度。着色器是在运行时定义的,但是当完成以后,用户可以改变要激活哪个着色器,并使用数据流动态地控制着色器。这在渲染像素的方法上,给了用户更高的灵活性。
顶点着色器文件包含顶点着色器指令。顶点着色器可以控制顶点颜色和把纹理应用于顶点的方式。也可以通过使用顶点着色器指令加入光照。着色器指令文件包含的是ASCII文本,因此它是可读的,并且看起来有点象汇编语言。顶点着色器在任何DrawPrimitive或DrawIndexedPrimitive之后被调用。用SetVertexShader指定新的着色器文件可以动态地切换着色器,也可以用数据流输入改变ASCII文本的着色器文件中的指令。Vertex_Shader_1_1中包含了着色器指令的完全列表。
指令集的变化非常快。为避免在使用指令时出现问题,请查阅硬件开发商的网站。或者,也可以使用高级着色器语言,这样就可以得到由Direct3D扩展(D3DX)编译得到的着色器指令。
创建顶点着色器
本示例创建一个顶点着色器,把一固定颜色应用于物体。本示例将会给出着色器文件的内容,以及为了在应用程序中使用该着色器而设置Microsoft® Direct3D®流水线所需的代码。
如果读者已经知道如何构建并运行Direct3D示例,那么可以从本示例中复制代码并粘贴到已有的应用程序中。
本文讨论了以下几个步骤。
第1步:声明顶点数据
本示例使用由两个三角形构成的四边形。顶点数据包含(x,y,z)位置和漫反射色。顶点数据在一个全局顶点数组(g_Vertices)中声明。四个顶点以原点为中心。
// 声明顶点数据结构。
struct CUSTOMVERTEX
{
FLOAT x, y, z;
};
// 声明顶点位置和漫反射色。
CUSTOMVERTEX g_Vertices[]=
{
// x y z
{ -1.0f, -1.0f, 0.0f },
{ +1.0f, -1.0f, 0.0f },
{ +1.0f, +1.0f, 0.0f },
{ -1.0f, +1.0f, 0.0f },
};
第2步:设计着色器的功能
该着色器将一固定颜色应用于每个顶点。以下为着色器文件VertexShader.vsh:
vs_1_1 // 版本指令
dcl_position v0 // 说明位置数据在寄存器v0中
m4x4 oPos, v0, c0 // 用视/投影矩阵变换顶点
mov oD0, c4 // 载入固定颜色
该文件包含了三条数据运算指令和一个寄存器定义。着色器文件的第一条指令必须是着色器版本声明。vs指令用来声明顶点着色器的版本,此处为1_1。
dcl_position指令把寄存器v0定义为顶点位置数据的源。m4x4指令用视/投影矩阵对物体的顶点进行变换。矩阵被载入并保存在常量寄存器c0, c1, c2, c3(如下所示)中。Mov指令把寄存器c4中的固定颜色复制到输出漫反射色寄存器oD0中。这导致输出顶点的颜色被改变。
第3步:检查对顶点着色器的支持
在使用顶点着色器之前,可以查询驱动程序对顶点着色器的支持。
D3DCAPS9 caps;
m_pd3dDevice->GetDeviceCaps(&caps); // 在使用前初始化m_pd3dDevice
if( caps.VertexShaderVersion < D3DVS_VERSION(1,1) )
return E_FAIL;
在调用IDirect3DDevice9::GetDeviceCaps后,caps结构会返回硬件可用的能力。应该用D3DVS_VERSION宏测试硬件支持的版本号。如果版本号小于1_1,那么该调用将会失败。这个方法的结果应该被应用程序用来控制是否使用顶点着色器。
第4步:声明顶点着色器数据
顶点声明用来描述顶点数据。
// 创建着色器声明。
D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
D3DDECL_END()
};
这个声明说明了以下这些:数据来自数据流0,从数据流起始位置起偏移量为0处的位置开始,声明位置数据为三个浮点数(D3DDECLTYPE_FLOAT3),告诉tessellator复制顶点数据(D3DDECLMETHOD_DEFAULT),定义数据的用途为顶点数据(D3DDECLUSAGE_POSITION),并说明用途索引为0。
D3DDECLEND()宏用来结束顶点声明。
第5步:创建着色器
下一步汇编并创建着色器。
LPDIRECT3DPIXELSHADER9 m_pVertexShader;
TCHAR strShaderPath[512];
LPD3DXBUFFER pCode; // 包含经过汇编的着色器代码的缓存
LPD3DXBUFFER pErrorMsgs; // 包含错误信息的缓存
DXUtil_FindMediaFileCb( strShaderPath, sizeof(strShaderPath),
_T("VertexShader.vsh") );
D3DXAssembleShaderFromFile( strPixelShaderPath, NULL, NULL, 0,
&pCode, &pErrorMsgs, NULL );
m_pd3dDevice->CreateVertexShader((DWORD*)pCode->GetBufferPointer(),
&m_pVertexShader)
pCode->Release();
pErrorMsgs->Release()
在定位了着色器文件后,D3DXAssembleShaderFromFile读取并验证着色器指令。然后IDirect3DDevice9::CreateVertexShader对指令进行汇编并创建着色器。该方法会返回用于绘制时调用的着色器对象。
CreateVertexShader用于创建一个可编程着色器。
第6步:渲染输出像素
这里是一份代码示例,可以用在渲染循环中用顶点着色器来渲染物体。由于三维场景的变化,渲染循环不断更新顶点着色器常数,并调用IDirect3DDevice9::DrawPrimitive绘制输出顶点。
// 用视/投影矩阵更新顶点着色器常数。
D3DXMATRIX mat, matView, matProj;
D3DXMatrixMultiply( &mat, &matView, &matProj );
D3DXMatrixTranspose( &mat, &mat );
m_pd3dDevice->SetVertexShaderConstantF( 0, (float*)&mat, 4 );
// 声明并定义固定的顶点颜色。
float color[4] = {0,1.0,0,0};
m_pd3dDevice->SetVertexShaderConstantF( 4, (float*)&color, 1 );
// 关闭镜面反射光,因为顶点着色器没有输出镜面反射光。
m_pd3dDevice->SetRenderState( D3DRS_SPECULAR, FALSE );
// 渲染输出。
m_pd3dDevice->SetStreamSource( 0, m_pQuadVB, sizeof(CUSTOMVERTEX) );
m_pd3dDevice->SetVertexShader( m_pVertexShader );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );
视和投影矩阵包含了摄像机的位置和方向的数据。因为场景可能在渲染得到的帧之间变化,所以渲染循环中要得到最新的数据,并用这些数据更新着色器的常量寄存器
IDirect3DDevice9::DrawPrimitive照常使用IDirect3DDevice9::SetStreamSource提供的数据渲染输出数据。IDirect3DDevice9::SetVertexShader是用来告诉Direct3D要使用顶点着色器。顶点着色器的结果如下图,它显示了在平面物体上的固定颜色。
顶点颜色
本示例把顶点数据中的顶点颜色应用于物体。顶点数据包含了位置和漫反射色。这些数据如下所示:
struct CUSTOMVERTEX_POS_COLOR
{
float x, y, z;
DWORD diffuseColor;
};
// 创建包含位置和纹理坐标的顶点数据。
CUSTOMVERTEX_POS_COLOR g_Vertices[]=
{
// x y z 漫反射色
{ -1.0f, 0.25f, 0.0f, 0xffff0000, }, // 右下 – 红
{ 0.0f, 0.25f, 0.0f, 0xff00ff00, }, // 左下 – 绿
{ 0.0f, 1.25f, 0.0f, 0xff0000ff, }, // 左上 – 蓝
{ -1.0f, 1.25f, 0.0f, 0xffffffff, }, // 右上 – 白
};
顶点着色器声明也需要反映位置和颜色数据。
// 创建着色器声明。
D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
D3DDECL_END()
};
着色器得到变换矩阵的一种方法是通过常量寄存器,常量寄存器是通过调用SetVertexShaderConstant设置的。
D3DXMATRIX mat;
D3DXMatrixMultiply( &mat, &m_matView, &m_matProj );
D3DXMatrixTranspose( &mat, &mat );
hr = m_pd3dDevice->SetVertexShaderConstantF( 1, (float*)&mat, 4 );
if(FAILED(hr))
return hr;
该声明声明了一个包含了位置和颜色数据的数据流。颜色数据被指定到寄存器1。以下是着色器代码。
vs_1_1 ; 版本指令
m4x4 oPos, v0, c0 ; 用视/投影矩阵变换顶点
mov oD0, v1 ; 从寄存器1载入颜色并赋给漫反射色
这个着色器包含三条指令。第一条总是版本指令。第二条指令用来变换顶点。第三条指令用来把顶点寄存器中的颜色复制到输出漫反射色寄存器中。结果是输出顶点使用了顶点的颜色数据。
得到的输出看起来如下所示:
纹理
本示例将一张纹理贴图应用于物体。
顶点数据包含了物体的位置和纹理坐标(uv)。这导致了顶点声明的改变。下面还显示了顶点数据。
struct CUSTOMVERTEX_POS_TEX1
{
float x, y, z; // 物体位置
float tu1, tv1; // 纹理坐标
};
CUSTOMVERTEX_POS_TEX1 g_Vertices[]=
{
// x y z u1 v1
{ -0.75f, -0.5f, 0.0f, 0.0f, 0.0f }, // 右下 – 红
{ 0.25f, -0.5f, 0.0f, 1.0f, 0.0f }, // 左下 – 绿
{ 0.25f, 0.5f, 0.0f, 1.0f, -1.0f }, // 左上 – 蓝
{ -0.75f, 0.5f, 0.0f, 0.0f, -1.0f }, // 右上 – 白
};
D3DUtil_CreateTexture( m_pd3dDevice, TEXT("earth.bmp"),
&m_pTexture0, D3DFMT_R5G6B5 );
必须先载入纹理的图像。在本例中,文件"earth.bmp"包含了地球的二维纹理贴图,并将被用来给物体着色。
顶点着色器声明需要反映出顶点位置和纹理坐标数据。
// 创建着色器声明。
D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
该声明声明了一个包含顶点位置和纹理坐标的数据流。
渲染代码告诉Microsoft® Direct3D®到何处去得到数据流和着色器,因为使用了纹理贴图,所以还要设置纹理层。
m_pd3dDevice->SetStreamSource( 0, m_pQuadVB, sizeof(CUSTOMVERTEX_POS_TEX1) );
m_pd3dDevice->SetVertexShader( m_pVertexShader );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTexture( 0, m_pTexture0 );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );
m_pd3dDevice->SetTexture( 0, NULL );
因为使用了一个纹理,所以需要设置纹理层0的纹理层状态。上面调用的方法告诉Direct3D纹理的texel值用来给物体的顶点提供漫反射色。换句话说,二维纹理贴图的使用就象贴花纸一样。
这里是着色器代码。
vs_1_1 // 版本指令
dcl_position v0 // 声明位置寄存器
dcl_texcoord v8 // 声明纹理坐标寄存器
def c4, 1, 1, 1, 1 // 初始化常量
m4x4 oPos, v0, c0 // 用视/投影矩阵变换顶点
mov oD0, c4 // 把漫反射色赋给输出颜色寄存器
mov oT0, v8 // 把纹理的颜色赋给纹理寄存器
着色器文件包含的这些指令会产生一个贴上了纹理的物体,如下所示。
带光照的纹理贴图
本实例使用了一个顶点着色器,将纹理贴图和光照应用于场景。这里使用的物体是一个球体,示例代码把地球的纹理贴图应用于球体,并用漫反射光照来模拟昼夜。
Shader3实例给贴上了纹理的物体添加了光照。关于如何载入纹理和设置纹理层状态的信息,请参阅Shader3。
在示例框架中有关于框架的示例代码的详细说明。读者可以复制这里的示例代码并粘贴到示例框架中去,这样就可以很快得到一个能运行的示例。
顶点着色器的创建
为了包含顶点法向,需要修改Shader3实例中的顶点数据。要产生光照,物体必须有顶点法向。修改后的顶点数据的数据结构如下所示。
struct CUSTOMVERTEX_POS_NORM_COLOR1_TEX1
{
float x, y, z; // 位置
float nx, ny, nz; // 法向
DWORD color1; // 漫反射色
float tu1, tv1; // 纹理坐标
};
着色器声明定义了输入顶点寄存器以及和它们关联的数据。
// 创建着色器声明。
D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 28, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
这里声明了一个数据流,其中包含了顶点位置,法向,漫反射色和纹理坐标。
下一步是创建着色器。可以用一个ASCII文本字符串创建着色器,也可以从包含相同指令的着色器文件中载入。本示例使用着色器文件。
// v7 用于光照的顶点漫反射色
// v8 纹理
// c4 视/投影矩阵
// c12 光的方向
vs_1_1 // 版本指令
dcl_position v0 // 声明寄存器数据
dcl_normal v4 // v0为位置,v4为法向
dcl_color0 v7 // v7为漫反射色
dcl_texcoord0 v8 // v8为纹理坐标
m4x4 oPos, v0, c4 // 用视/投影矩阵变换顶点
dp3 r0, v4, c12 // 执行世界空间中的光照计算N dot L
mul oD0, r0.x , v7 // 根据光强度和经插值的顶点漫反射色计算像素的最终颜色
mov oT0.xy , v8 // 将纹理坐标得到到输出
第一条总是版本指令,最后一条指令把纹理数据复制到输出寄存器oT0。写完了着色器指令后,就可以用来创建着色器。
LPDIRECT3DPIXELSHADER9 m_pVertexShader;
TCHAR strShaderPath[512];
LPD3DXBUFFER pCode; // 包含汇编后的着色器代码的缓存
LPD3DXBUFFER pErrorMsgs; // 包含错误信息的缓存
DXUtil_FindMediaFileCb( strShaderPath, sizeof(strShaderPath),
_T("VertexShader3.vsh") );
D3DXAssembleShaderFromFile( strPixelShaderPath, NULL, NULL, 0,
&pCode, &pErrorMsgs, NULL );
m_pd3dDevice->CreateVertexShader((DWORD*)pCode->GetBufferPointer(),
&m_pVertexShader)
pCode->Release();
pErrorMsgs->Release();
在定位了文件后,Microsoft® Direct3D®会创建顶点着色器并返回着色器对象。本示例用了一个着色器文件,这样调用一个方法就可以创建着色器。另一种方法是创建一个包含着色器指令的ASCII文本字符串。
顶点着色器常量
可以在着色器外定义顶点着色器常量,如以下示例所示。此处,常量用来给着色器提供视/投影矩阵,漫反射光颜色RGBA和光的方向向量。
float constants[4] = {0, 0.5f, 1.0f, 2.0f};
m_pd3dDevice->SetVertexShaderConstantF( 0, (float*)&constants, 1 );
D3DXMATRIX mat;
D3DXMatrixMultiply( &mat, &m_matView, &m_matProj );
D3DXMatrixTranspose( &mat, &mat );
m_pd3dDevice->SetVertexShaderConstantF( 4, (float*)&mat, 4 );
float color[4] = {1,1,1,1};
m_pd3dDevice->SetVertexShaderConstantF( 8, (float*)&color, 1 );
float lightDir[4] = {-1,0,1,0}; // fatter slice
m_pd3dDevice->SetVertexShaderConstantF( 12, (float*)&lightDir, 1 );
也可以在着色器内部用def指令定义常量。
渲染
在写完着色器指令后,要将顶点数据与正确的顶点寄存器连接并初始化常量,然后渲染输出。渲染代码告诉Direct3D到哪里去得到顶点缓存的数据流,并给Direct3D提供着色器的句柄。因为使用了纹理,所以还必须设置纹理层以告诉Direct3D如何使用纹理数据。
// 设置顶点缓存的数据源。
m_pd3dDevice->SetStreamSource(0, m_pVB, sizeof(CUSTOMVERTEX_POS_NORM_COLOR1_TEX1));
// 设置着色器。
m_pd3dDevice->SetVertexShader( m_pVertexShader );
// 设置用到的纹理和纹理层状态。
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTexture( 0, m_pTexture0 );
// 绘制物体。
DWORD dwNumSphereVerts = 2 * m_dwNumSphereRings*(m_dwNumSphereSegments + 1);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, dwNumSphereVerts - 2);
下面是输出的图像。
贴了纹理后,球体看起来像是地球。光照在球体表面产生了从亮到暗的变化。
将顶点着色器与顶点声明分离
在Microsoft® DirectX® 9.0中,顶点着色器和顶点声明不再是在创建顶点着色器(CreateVertexShader)的时候绑定在一起。对着色器的验证已经被分成两部分,一部分在顶点着色器创建时执行,另一部分在绘制(DrawPrimitive)时执行。
- 把DirectX 8.x的顶点声明映射到DirectX 9.0的顶点声明
- 把FVF码映射到DirectX 9.0的顶点声明
- 把DirectX 9.0的顶点声明映射到DirectX 8.x的顶点声明
- 把DirectX 9.0的顶点声明映射到FVF码
顶点着色器和顶点声明都由相应的对象表示。为了使之能与DirectX 8.x驱动程序一起工作,Direct3D进行了一些高速缓存。在“绘制的时候”,运行库会检查是否存在一个组合着色器对象,该对象封装了当前声明和着色器。如果存在,那么运行库会将它送给驱动程序,反之,运行库会为当前着色器和声明的组合创建一个新的组合着色器对象。另外,为了解决API的可用性问题,9.0版增加了一个与SetVertexDeclaration调用等价的SetFVF调用。这是一个有用的函数,当调用这个函数时,新的FVF会取代当前的顶点声明,反之亦然。如果驱动程序是DirectX 8.0之前的版本(NumStream为0),那么对于那些不能被转换成弹性顶点格式(FVF)的顶点声明,SetVertexDeclaration可能会失败并返回错误码。
- SetVertexDeclaraion和SetVertexShader调用会被状态块记录。设置或取得着色器或声明会导致该对象的引用计数的增加。
- FVF码既可以用于固定功能流水线,又能用于可编程顶点流水线。FVF要根据转换表,被转换为顶点着色器声明。在写顶点着色器函数中的DCL命令时,应该紧记这一点。
- 软件顶点处理支持DirectX 9.0级别的特性,也支持tessellation,因此在用软件顶点处理进行绘制时,可以使用更多的声明。
- 对可编程顶点流水线而言:在绘制的时候,Microsoft® Direct3D®会在当前的顶点声明和当前的顶点着色器函数中查找相同的“用途 – 用途索引”组合。如果找到了这样的组合,那么着色器函数中DCL声明的寄存器会被用作顶点元素的目标寄存器。
- 如果FVF包含了XYZRHW位置类型,那么顶点被认为是经过变换和经过光照处理的,在用于可编程顶点流水线时,不会应用顶点着色器函数。
- 如果当前顶点声明中的一个顶点元素的用途无法在当前顶点着色器中找到,那么该顶点元素就被忽略。
在DirectX 8.x驱动程序(numstrems不为零,但不支持数据流偏移量)上允许使用声明的一个子集,只能创建那些可被转换为 DirectX 8.x风格的声明。由于这个原因,如果声明不能被转换,那么CreateVertexDeclaration调用可能会失败。对混合模式设备来说,此类失败会发生在Drawxxx的时候,因为只有这时候才能知道着色器是被用于硬件还是软件顶点处理。表中概括了这类转换。
在DirectX 8.0之前的驱动程序(numstreams为零)上允许使用一个更小的子集,只能使用那些可被转换为FVF的声明。如果无法进行转换,那么CreateVertexDeclaration可能会失败。对混合模式设备来说,此类失败会发生在Drawxxx的时候,因为只有这时候才能知道着色器是被用于硬件还是软件顶点处理。表中概括了这类转换。只能使用数据流0(显然可以从MaxStreams设备能力中看出)。
顶点元素的顺序应该和FVF码相对应,D3DDECLUSAGE_POSITION和D3DDECLUSAGE_NORMAL的用途索引应该为零。使用混合顶点处理的设备时,如果要切换顶点处理模式,那么无需重置所有的输入顶点(和索引)数据流,顶点声明和顶点函数。不能用NULL作为SetVertexDeclaration的输入。在使用软件顶点处理时,可编程顶点流水线的着色器代码中用到的用途也应该存在于在绘制的时候与之绑定的声明(或FVF)中。
符合以下规则的声明可以用来在固定功能流水线(假设不需要tessellation)中进行渲染。
- 只使用D3DDECLMETHOD_DEFAULT。
- 顶点元素之间不能有间隔(SKIP在DirectX 8.x声明中是不允许的)
- 指定POSITION用途。
- 为POSITION用途指定D3DDECLTYPE_FLOAT3数据类型。
- 下表中没有描述的顶点元素在所有DirectX 8.0之前的驱动程序上都无法被转换为有效的FVF码,因此无法用于固定功能顶点处理。
把DirectX 8.x的顶点声明映射到DirectX 9.0的顶点声明
DirectX 8.x | DirectX 9.0 用途 | DirectX 9.0 用途索引 |
D3DVSDE_POSITION | D3DDECLUSAGE_POSITION | 0 |
D3DVSDE_POSITION2 | D3DDECLUSAGE_POSITION | 1 |
D3DVSDE_NORMAL | D3DDECLUSAGE_NORMAL | 0 |
D3DVSDE_NORMAL2 | D3DDECLUSAGE_NORMAL | 1 |
D3DVSDE_BLENDWEIGHT | D3DDECLUSAGE_BLENDWEIGHT | 0 |
D3DVSDE_BLENDINDICES | D3DDECLUSAGE_BLENDINDICES | 0 |
D3DVSDE_PSIZE | D3DDECLUSAGE_PSIZE | 0 |
D3DVSDE_DIFFUSE | D3DDECLUSAGE_COLOR | 0 |
D3DVSDE_SPECULAR | D3DDECLUSAGE_COLOR | 1 |
D3DVSDE_TEXCOORDn | D3DDECLUSAGE_TEXCOORD | n |
把FVF码转换为DirectX 9.0的顶点声明
FVF | 数据类型 | 用途 | 用途索引 |
D3DFVF_XYZ | D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_POSITION | 0 |
D3DFVF_XYZRHW | D3DDECLTYPE_FLOAT4 | D3DDECLUSAGE_POSITIONT | 0 |
D3DFVF_XYZW | D3DDECLTYPE_FLOAT4 | D3DDECLUSAGE_POSITIONT | 0 |
D3DFVF_XYZB5 and D3DFVF_LASTBETA_UBYTE4 | D3DVSDT_FLOAT3, D3DVSDT_FLOAT4, D3DVSDT_UBYTE4 | D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES | 0 |
D3DFVF_XYZB5 | D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT4, D3DDECLTYPE_FLOAT1 | D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES | 0 |
D3DFVF_XYZBn (n=1..4) | D3DDECLTYPE_FLOAT3 D3DDECLTYPE_FLOATn | D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT | 0 |
D3DFVF_XYZBn (n=1..4) and D3DFVF_LASTBETA_UBYTE4 | D3DDECLTYPE_FLOAT3 D3DDECLTYPE_FLOAT(n-1) D3DDECLTYPE_UBYTE4 | D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES | 0 |
D3DFVF_NORMAL | D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_NORMAL | 0 |
D3DFVF_PSIZE | D3DDECLTYPE_FLOAT1 | D3DDECLUSAGE_PSIZE | 0 |
D3DFVF_DIFFUSE | D3DDECLTYPE_D3DCOLOR | D3DDECLUSAGE_COLOR | 0 |
D3DFVF_SPECULAR | D3DDECLTYPE_D3DCOLOR | D3DDECLUSAGE_COLOR | 1 |
D3DFVF_TEXCOORDSIZEm(n) | D3DDECLTYPE_FLOATm | D3DDECLUSAGE_TEXCOORD | n |
把DirectX 9.0的顶点声明转换为DirectX 8.x的顶点声明
用途 | 用途索引 | DirectX decl |
D3DDECLUSAGE_POSITION | 0 | D3DVSDE_POSITION |
D3DDECLUSAGE_POSITION | 1 | D3DVSDE_POSITION2 |
D3DDECLUSAGE_BLENDWEIGHT | 0 | D3DVSDE_BLENDWEIGHT |
D3DDECLUSAGE_BLENDINDICES | 0 | D3DVSDE_BLENDINDICES |
D3DDECLUSAGE_NORMAL | 0 | D3DVSDE_NORMAL |
D3DDECLUSAGE_NORMAL | 1 | D3DVSDE_NORMAL2 |
D3DDECLUSAGE_PSIZE | 0 | D3DVSDE_PSIZE |
D3DDECLUSAGE_COLOR | 0 | D3DVSDE_DIFFUSE |
D3DDECLUSAGE_COLOR | 1 | D3DVSDE_SPECULAR |
D3DDECLUSAGE_TEXCOORD | n | D3DVSDE_TEXTUREn, n <= 7 |
把DirectX 9.0的顶点声明转换为FVF码
在DirectX 8.0及以后的驱动程序上,更多的类型可以成功地被转换为有效的声明,因此可以被用于固定功能顶点处理。
- 如果使用了DirectX 8.x驱动程序,那么顶点声明会根据以下规则被转换为DirectX 8.x的声明。如果使用其它的用途组合,那么对Direct3D的调用会失败。
- 对于D3DVSD_STREAM中每个新的数据流,会插入一个标记(token)。
- 顶点元素不能共享数据流中相同的偏移量,并且不能重叠。
- 数据类型必须小于或等于D3DDECLTYPE_SHORT4。
- 对于每个使用了D3DDECLMETHOD_DEFAULT方法的顶点元素,会插入D3DVSD_REG标记。
- Usage和UsageIndex会根据下表被转换为寄存器值。如果使用DrawRectPatch(RT-patches),那么tessellator的输出应该符合前面的规则。
数据类型 | 用途 | 用途索引 | FVF |
D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_POSITION | 0 | D3DFVF_XYZ |
D3DDECLTYPE_FLOATn | D3DDECLUSAGE_BLENDWEIGHT | 0 | D3DFVF_XYZBn |
D3DDECLTYPE_UBYTE4 | D3DDECLUSAGE_BLENDINDICES | 0 | D3DFVF_XYZB (nWeights+1) |
D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_NORMAL | 0 | D3DFVF_NORMAL |
D3DDECLTYPE_FLOAT1 | D3DDECLUSAGE_PSIZE | 0 | D3DFVF_PSIZE |
D3DDECLTYPE_D3DCOLOR | D3DDECLUSAGE_COLOR | 0 | D3DFVF_DIFFUSE |
D3DDECLTYPE_D3DCOLOR | D3DDECLUSAGE_COLOR | 1 | D3DFVF_SPECULAR |
D3DDECLTYPE_FLOATm | D3DDECLUSAGE_TEXCOORD | n | D3DFVF_TEXCOORDSIZEm(n) |
D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_POSITION | 1 | N/A |
D3DDECLTYPE_FLOAT3 | D3DDECLUSAGE_NORMAL | 1 | N/A |