|
目录 1、初始化 2、Render 3、.VSH文件 4、使用纹理 5、使用光照 6、VertexShader的结构 7、寄存器的性质 8、各向异性
参考资料: 强烈建议看DX9SDK,里面有十分详尽的1.1到3.0的参考手册 SDK理论:Direct3D Architecture::Programmable Vertex Shader Architecture SDK实例:ProgrammablePipeline::VertexShaders
1、初始化部分,D3DVSD_STREAM、D3DVSD_REG、D3DVSD_END用于定义顶点数据存储格式,D3DXAssembleShaderFromFile从.VSH文件中调入VertexShader处理程序,CreateVertexShader用于创建VertexShader,SetVertexShaderConstant用于设置寄存器参数,SetVertexShader用于设置VertexShader。我的显卡VertexShader版本是1.1,PixelShader的版本是0.0,看来是硬件不支持了。
//版本检测 D3DCAPS8 caps; ZeroMemory(&caps,sizeof(caps)); m_pD3DDevice->GetDeviceCaps(&caps);
m_Debug.Add("VertexShader version:%x.%x", D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion), D3DSHADER_VERSION_MINOR(caps.VertexShaderVersion));
void CVShader::LoadVSH( TCHAR* strFilename ) { // Create the vertex shader.开始创建VS LPD3DXBUFFER pCode; DWORD dwDecl2[] = { D3DVSD_STREAM(0), D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR ), D3DVSD_END() };
// Assemble the vertex shader from the file.读取VSH文件 if( FAILED( D3DXAssembleShaderFromFile( strFilename, 0, NULL, &pCode, NULL ) ) ) { return; }
// Create the vertex shader.建立VS if(SUCCEEDED( m_pD3DDevice->CreateVertexShader( dwDecl2, (DWORD*)pCode->GetBufferPointer(), &m_dwVertexShader, 0 ))) { pCode->Release(); }
} |
2、Render部分,需要matWorld、m_matView和m_matProj三个矩阵来对顶点处理。
m_pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
D3DXMATRIX mat; D3DXMatrixMultiply( &mat, &matWorld, &m_pCamera->m_matView ); D3DXMatrixMultiply( &mat, &mat, &m_pCamera->m_matProj ); D3DXMatrixTranspose( &mat, &mat ); m_pD3DDevice->SetVertexShaderConstant( 0, &mat, 4 ); //将WVP矩阵设置在c0
float color[4] = {0,1,0,0}; //RGBA m_pD3DDevice->SetVertexShaderConstant( 4, &color, 1 ); //将指定颜色设置在c4
m_pD3DDevice->SetVertexShader( m_dwVertexShader );
//渲染 m_pD3DDevice->SetTexture(0, m_pTextures); m_pD3DDevice->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) ); m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 ); |
3、Test.VSH文件,将 mov oD0, c4 改为 mov oD0, v5 可以显示原有颜色。
vs.1.0 m4x4 oPos, v0, c0 ; transform vertices by view/projection matrix,WMP矩阵变换顶点坐标 mov oD0, c4 ; load color from register 4 to diffuse color,设置顶点颜色
结果如图所示:
 |
4、使用纹理
struct CUSTOMVERTEX { float x, y, z; DWORD color; float tu,tv; };
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
CUSTOMVERTEX m_Vertices[] = { { -1.0f, 0.0f, 0.0f, 0xffff0000, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 0xff0000ff, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.732f, 0xffffffff, 0.0f, 0.0f }, };
DWORD dwDecl2[] = { D3DVSD_STREAM(0), D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR ), D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2 ), D3DVSD_END() };
vs.1.0 m4x4 oPos, v0, c0 mov oT0, v7 ; move texture color to output texture register,设置纹理坐标
结果如图所示:
 |
5、使用光照
struct CUSTOMVERTEX { float x, y, z; float nx, ny, nz; DWORD color; float tu,tv; };
CUSTOMVERTEX m_Vertices[] = { { -1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0xffff0000, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0xff0000ff, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.732f, 0.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f }, };
DWORD dwDecl2[] = { D3DVSD_STREAM(0), D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), //v0,pos,顶点坐标设置在v0 D3DVSD_REG(D3DVSDE_NORMAL , D3DVSDT_FLOAT3), //v3,nor,顶点法线设置在v3 D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR ), //v5,color,顶点diffuse颜色设置在v5 D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2 ), //v7,tex,纹理坐标设置在v7 D3DVSD_END() };
float lightDir[4] = {-1,-1,1,0}; // fatter slice m_pD3DDevice->SetVertexShaderConstant( 12, &lightDir, 1 );
vs.1.0 m4x4 oPos, v0, c0 dp3 r0 , v3 , c12 // perform lighting N dot L calculation,计算法线点乘光线 mul oD0 , r0.x , v5 // calculate final pixel color from light intensity,根据光线强度计算颜色 // and interpolated diffuse vertex color mov oT0.xy , v7 // copy texture coordinates to output,输出纹理坐标
结果如图所示:
 |
6、VertexShader的结构。VertexShader与T&L在Render流程中处于二选一的同等地位,我甚至怀疑T&L只是一种特殊的VertexShader(hoho,理论不行,恶补中...)。VertexShader算逻单元(ALU)有顶点数据寄存器(v0-15)、临时寄存器(r0-11)、常数寄存器(c0-95)、地址寄存器(a0)和若干输出寄存器,每个寄存器存储一个4D的矢量(4个32位的浮点数共128位)。 DirectX 8.x中,一个VertexShader程序最多只能有128条指令,只能线性执行指令(没有循环、条件判断、跳转指令),同时只能有一个VertexShader程序被激活(无法将两个VertexShader程序依次执行,也就是要为每个特定的效果编写独立的程序)。 通过前面3个例子总算有了一点感性认识。
 图一、D3D的Render流程
 图二、Vertex Shader的结构
|
7、寄存器的性质。主要是读写属性、数量,特别是每条指令中能出现的次数。象 add oD0, v5, v5 这种指令在1.0版本中是无效的,在1.1版本中就可以了,效果见下图。
表一、性质列表
Name |
Type |
I/O Permissions |
Count |
Number allowed per instruction |
Versions |
a0 |
address register |
write/use only |
1 scalar |
0 in version 1.0; 1 in version 1.1 |
1.0 - 1.1 |
cn |
constant register |
read-only |
96 vectors |
1 |
1.0 - 1.1 |
rn |
temporary register |
read/write |
12 vectors |
3 |
1.0 - 1.1 |
vn |
vertex register |
read-only |
16 vectors |
1 in version 1.0; 2 in version 1.1 |
1.0 - 1.1 |
vs.1.0 m4x4 oPos, v0, c0 add oD0, v5, v5

|
8、各向异性效果。
; v0 -- position ; v3 -- normal ; v7 -- tex coord ; v8 -- tex coord1 ; ; c0-3 -- world/view/proj matrix ; c4 -- light vector ; c5-8 -- inverse/transpose world matrix ; c9 -- {0.0, 0.5, 1.0, -1.0} ; c10 -- eye point ; c11-14 -- world matrix
vs.1.0
;transform position dp4 oPos.x, v0, c0 dp4 oPos.y, v0, c1 dp4 oPos.z, v0, c2 dp4 oPos.w, v0, c3
;transform normal dp3 r0.x, v3, c5 dp3 r0.y, v3, c6 dp3 r0.z, v3, c7
;normalize normal dp3 r0.w, r0, r0 rsq r0.w, r0.w mul r0, r0, r0.w
;compute world space position dp4 r1.x, v0, c11 dp4 r1.y, v0, c12 dp4 r1.z, v0, c13 dp4 r1.w, v0, c14
;vector from point to eye add r2, c10, -r1
;normalize e dp3 r2.w, r2, r2 rsq r2.w, r2.w mul r2, r2, r2.w
;h = Normalize( l + e ) add r1, r2, c4
;normalize h dp3 r1.w, r1, r1 rsq r1.w, r1.w mul r1, r1, r1.w
;l dot n dp3 oT0.x, r0, c4
;h dot n dp3 oT0.y, r1, r0

| |