一次只有一个vertex shader是活跃的。你可以有多个vertex shader,如果一个物体特殊的变换或者灯光,你可以选择合适的vertex shader来完成这个任务。
你可能想使用vertex shaders在每个物体或每个网格上,例如,十个网格,你可以使用十个不同的vertex shader,但那样可能会harm你的游戏的运行。
每个vertex shader-driven程序必须通过下面的步骤运行:
1。检查你的设备是否支持vertex shader。 (在direct X9以后已经不需要了)
2。用D3DVSD_* 宏声明vertex shader,用于将顶点缓冲(vertex buffer streams)映射(map)到输入寄存器(input register)。
3。用SetVertexShaderConstant()设置顶点着色器的常量寄存器。
4。用D3DXAssembleShader*()编译事先写的顶点着色器。
5。用CreateVertexShader()创建一个顶点着色器句柄。
6。用SetVertexShader()为一个要特效化的物体设置顶点着色器。
7。用DeleteVertexShader()删除顶点着色器。
由于第一步在directX 9以后就不需要了,所以这里省略它。
以下实现均对应于上述步骤。
---------------------------------------------------------------------------------------------------------------------------------------------------------------
2。声明顶点着色器。
在使用一个顶点着色器之前必须声明它。这个声明可以被称作一个静态的外部接口。
1 float c[4] = {0.0f,0.5f,1.0f,2.0f}; 2 DWORD dwDesc10[] = { 3 D3DVSD_STREAM(0), 4 D3DVSD_REG(0,D3DVSDT_FLOAT3), //input register v0 5 D3DVSD_REG(5,D3DVSDT_D3DCOLOR), //input register v5 6 7 // set a few constants 8 D3DVSD_CONST(0,1), 9 *(DWORD*)&c[0], 10 *(DWORD*)&c[1], 11 *(DWORD*)&c[2], 12 *(DWORD*)&c[3], 13 D3DVSD_END() 14 };
这个顶点着色器声明用D3DVSD_STREAM(0)设置数据流0。之后,通过使用这个声明,SetStreamSource()绑定一个顶点缓冲区到设备数据流。
你必须声明哪一个输入顶点属性或输入顶点数据被映射到哪一个输入寄存器。D3DVSD_REG从顶点流中绑定一个单个的顶点寄存器到一个顶点元素。在我们这个声明的例子中,D3DVSD_FLOAT3值应该被放在第一个输入寄存器,而D3DVSD_D3DCOLOR颜色值应该被放在第六个输入寄存器。例如,位置数据可以被输入寄存器0(v0)用D3DVSD_REG(0,D3DVSDT_FLOAT3)处理,法线数据可以被输入寄存器3(v3)用D3DVSD_REG(3,D3DVSDT_FLOAT3)处理。
注意,除非你想使用N-Patches,这需要位置数据在v0,法线数据在v3,否则,开发者可以自由定义顶点数据输入到的寄存器的映射。
相比之下,在固定管线中,顶点数据输入到特定寄存器的映射是固定的。
D3DVSD_CONST将常量值载入到顶点着色器的常量寄存器。第一个参数是常量数组开始填充数据的开始位置,可能的值范围是0-95(in the case of the RADEON 8500, from 0-191.)我们在0处开始。第二个参数是要载入的常量向量的数目,如果你要载入一个4x4矩阵(也就是4个向量),可以如下载入:
1 float c[16] = (0.0f, 0.5f, 1.0f, 2.0f, 2 0.0f, 0.5f, 1.0f, 2.0f, 3 0.0f, 0.5f, 1.0f, 2.0f, 4 0.0f, 0.5f, 1.0f, 2.0f); 5 D3DVSD_CONST(0, 4), *(DWORD*)&c[0],*(DWORD*)&c[1],*(DWORD*)&c[2],*(DWORD*)&c[3], 6 *(DWORD*)&c[4],*(DWORD*)&c[5],*(DWORD*)&c[6],*(DWORD*)&c[7], 7 *(DWORD*)&c[8],*(DWORD*)&c[9],*(DWORD*)&c[10],*(DWORD*)&c[11], 8 *(DWORD*)&c[12],*(DWORD*)&c[13],*(DWORD*)&c[14],*(DWORD*)&c[15],
D3DVSD_END生成一个END,标志顶点着色器的结束。
1 D3DVSD_END()
3。SetVertexShaderConstant() 设置顶点着色器常量寄存器
你可以用SetVertexShaderConstant()填充顶点着色器常量寄存器,用GetVertexShaderConstant()得到这些寄存器中的值。
SetVertexShaderConstant()的声明如下:
HRESULT SetVertexShaderConstant( DWORD Register, CONST void* pConstantData, DWORD ConstantCount);
设置顶点着色器常量:
m_pd3dDevice->SetVertexShaderConstant( 0, &vZero, 1 ); m_pd3dDevice->SetVertexShaderConstant( 1, &vOne, 1 ); m_pd3dDevice->SetVertexShaderConstant( 2, &vWeight, 1 ); m_pd3dDevice->SetVertexShaderConstant( 4, &matTranspose, 4 ); m_pd3dDevice->SetVertexShaderConstant( 8, &matCameraTranspose, 4 ); m_pd3dDevice->SetVertexShaderConstant( 12, &matViewTranspose, 4 ); m_pd3dDevice->SetVertexShaderConstant( 20, &fLight, 1 ); m_pd3dDevice->SetVertexShaderConstant( 21, &fDiffuse, 1 ); m_pd3dDevice->SetVertexShaderConstant( 22, &fAmbient, 1 ); m_pd3dDevice->SetVertexShaderConstant( 23, &fFog, 1 ); m_pd3dDevice->SetVertexShaderConstant( 24, &fCaustics, 1 ); m_pd3dDevice->SetVertexShaderConstant( 28, &matProjTranspose, 4 );
如之前所述,至少有96个常量寄存器可以被填充。SetVertexShaderConstant()第一个参数为寄存器的索引,最后一个参数为常量的数目。比如,matViewTranspose将被载入到寄存器12,载入数目为4个,寄存器16-19未被使用,fLight被载入到寄存器20,载入数目为1. 那么 ,用在着色器声明中的D3DVSD_CONST和SetVertexShaderConstant()有什么不同呢?D3DVSD_CONST只能是用仅仅一次,而SetVertexShaderConstant()可以在每次DrawPrimitive*()之前调用。待续.....