|
目录 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

|
|
|