|
http://home.g365.net/coolvoldo/dx81/VShader/VS.htm
目录
参考文献
VS简介
VS寄存器
VS指令
我的代码
VS代码示例
我的学习笔记
设置c寄存器的三种方法
参考文献
SDK::Vertex Shader Architecture
SDK::VertexShaders
SDK: irect3DDevice8部分函数
SDK::Shader Functions部分函数
SDK::Vertex Shader Declarator Macros
Wolfgang::Fundamentals of Vertex Shaders 网址
Wolfgang: rogramming Vertex Shaders 网址
VertexShader简介
VertexShader与T&L在Render流程中处于二选一的同等地位,主要作用是对于每个顶点,根据顶点数据以及给定的光照、纹理等信息计算顶点的位置、颜色、纹理等结果。Fixed T&L其运作方式基本和VS一致,看作是系统固化的一种特殊的VS。
VS算逻单元(ALU)有顶点寄存器(v0-15)、临时寄存器(r0-11)、常量寄存器(c0-95)、地址寄存器(a0)和若干输出寄存器,每个寄存器为xyzw4个float结构(4个4字节共32位的浮点数共128位):
DirectX 8.x中,一个VertexShader程序最多只能有128条指令,只能线性执行指令(没有循环、条件判断、跳转指令),同时只能有一个VertexShader程序被激活(无法将两个VertexShader程序依次执行,也就是要为每个特定的效果编写独立的程序)。
硬件支持方面,GF3以前的显卡和GF4MX硬件不支持VS只能有软件模拟,GF3和GF4这些硬件支持DX8.1级别的显卡支持VS 1.1,GFFX硬件支持DX9,至少支持VS 2.0。ATI显卡的数据不详,而且好像没听说只支持VS 1.0而不支持VS1.1的显卡,有待查证。
VS寄存器(DX8.1)
输入寄存器
表一、输入寄存器性质列表
名称 类型 I/O 权限 数目 每条指令中的出现次数
a0 地址寄存器 write/use only 1 scalar 0 in VS 1.0; 1 in VS 1.1
cn 常量寄存器 read-only 96 vectors 1
rn 临时寄存器 read/write 12 vectors 3
vn 顶点寄存器 read-only 16 vectors 1 in VS 1.0; 2 in VS 1.1
顶点寄存器(Vertex Register,v0~v15)
根据程序设置的流的定义,单流或者多流的顶点数据按指定方式进入只读的顶点寄存器(v0~v15,共16个4*float结构,因为每个float是4字节32位,所以4*float结构也常被翻译成128位的4D矢量,这是寄存器里面的基本存储单位)。VS 1.0中,每条指令中v寄存器只能出现1次,VS 1.1中增加到2次,例如象 add oD0, v5, v5 这种指令在VS 1.0版本中是非法的,而在VS 1.1中是有效的。
地址寄存器(Address Register,a0.x)
在VS 1.1才开始被支持(VS 1.0中如果使用了a0寄存器,将不能通过VS编译),a0.x被用作一个4字节的有符号整型变量,用于在c寄存器中进行相对偏移寻址,例如:c[a0.x + n]。a0寄存器只能用mov指令赋值(未赋值直接使用,将不能通过VS编译),a0寄存器不能被读取。
常量寄存器(Constant Register,c0~c95)
用于存储矩阵、材质、光线、常数等一切有用或者没用的数据,结构为96个4*float结构的只读寄存器,在每条指令中c寄存器只能出现1次。实际上,显卡支持的c寄存器的数目可以在D3DCAPS8结构的MaxVertexShaderConst成员中得到,ATI RADEOM 8500中具有192个c寄存器c0-c191,应该很少会专为它写代码吧-_-。
c寄存器是只读寄存器是对于VS指令来说的,程序中可以使用SetVertexShaderConstant设置c寄存器的数值,或者在创建VS的时候使用常量定义,这样在每次SetVertexShader函数被调用的时候,将自动加载指定的c寄存器的值,具体可参见设置c寄存器的三种方法。
临时寄存器(Temporary Register,r0~r11)
临时寄存器是最接近普通寄存器的一个了,结构为12个4*float结构的可读写寄存器,在每条指令中可以出现3次(差不多算没有限制了),未赋值直接使用r寄存器,将不能通过VS编译。
输出寄存器
表二、输出寄存器性质列表
名称 类型 I/O 权限 数目 版本
oD0, oD1 颜色寄存器 write only 2 vectors VS 1.0~1.1
oFog 雾寄存器 write only 1 scalar VS 1.0~1.1
oPos 位置寄存器 write only 1 vectors VS 1.0~1.1
oPts 点尺寸寄存器 write only 1 scalar VS 1.0~1.1
oT0 - oT7 纹理坐标寄存器 write only 8 vectors VS 1.0~1.1
位置寄存器(Position Register,oPos)
只写寄存器,用于存储顶点在剪裁空间的坐标。
纹理坐标寄存器(Texture Coordinate Register,oT0~oT7)
8个只写寄存器,每个纹理Stage的纹理坐标。
颜色寄存器(Vertex Color Register,oD0,oD1)
2个只写寄存器,oD0保留漫反射diffuse结果,将被插值后写入PS的颜色输入寄存器v0;oD1保留镜面反射specular结果,将被插值后写入PS的颜色输入寄存器v1。
点尺寸寄存器(Point Size Register,oPts)
只写寄存器,仅oPts.x可用。
雾寄存器(Fog Register,oFog)
只写寄存器,仅oFog.x可用。The value is the fog factor to be interpolated and then routed to the fog table.Values are clamped between zero and one before passing to the rasterizer.
VS指令说明
Version Instructions
vs
vs.mainVer.subVer
用于指定VS的版本,例如vs.1.1
def
def dest, fVal0, fVal1, fVal2, fVal3
用于定义c寄存器,本语句应紧接在vs语句之后,具体可参见设置c寄存器的三种方法。
General Instructions
add
add dest, src0, src1
加法计算指令,可在寄存器前加上减号来做减法操作,如:add r1,v0,-v3。
dp3
dp3 dest, src0, src1
三元数点乘,dest.x = dest.y = dest.z = dest.w = (src1.x * src2.x) + (src1.y * src2.y) + (src1.z * src2.z)。
dp4
dp4 dest, src0, src1
四元数点乘,dest.x = dest.y = dest.z = dest.w = (src1.x * src2.x) + (src1.y * src2.y) + (src1.z * src2.z)+ (src1.w * src2.w)。
dst
dst dest, src0, src1
操作结果如下:
dest.x = 1;
dest.y = src0.y * src1.y;
dest.z = src0.z;
dest.w = src1.w;
主要用于点光源衰减的计算,当src0=d*d,src1=1/d时,结果dest为(1,d,d*d,1/d),点光源衰减计算的例子如下:
; r7.w = distance * distance = (x*x) + (y*y) + (z*z)
dp3 r7.w, VECTOR_VERTEXTOLIGHT, VECTOR_VERTEXTOLIGHT
; VECTOR_VERTEXTOLIGHT.w = 1/sqrt(r7.w)
; = 1/||V|| = 1/distance
rsq VECTOR_VERTEXTOLIGHT.w, r7.w
; Get the attenuation
; d = distance
; Parameters for dst:
; src1 = (ignored, d * d, d * d, ignored)
; src2 = (ignored, 1/d, ignored, 1/d)
;
; r7.w = d * d
; VECTOR_VERTEXTOLIGHT.w = 1/d
dst r7, r7.wwww, VECTOR_VERTEXTOLIGHT.wwww
; dest.x = 1
; dest.y = src0.y * src1.y
; dest.z = src0.z
; dest.w = src1.w
; r7(1, d * d * 1 / d, d * d, 1/d)
; c[LIGHT_ATTENUATION].x = a0
; c[LIGHT_ATTENUATION].y = a1
; c[LIGHT_ATTENUATION].z = a2
; (a0 + a1*d + a2* (d * d))
dp3 r7.w, r7, c[LIGHT_ATTENUATION]
; 1 / (a0 + a1*d + a2* (d * d))
rcp ATTENUATION.w, r7.w
; Scale the light factors by the attenuation
mul r6, r5, ATTENUATION.w
expp
expp dest, src
一般用与计算2的次方,例如:expp r1.x, c6.y后,r1.x等于2的c6.y次方,其他应用不详。
lit
lit dest, src
用于镜面反射计算?
logp
logp dest, src
计算log2(x),例如:logp r0, r0.w。
mad
mad dest, src0, src1, src2
dest.x = src0.x * src1.x + src2.x;
乘加操作,yzw类似。
max
max dest, src0, src1
dest.x=(src0.x >= src1.x) ? src0.x : src1.x;
取较大者,yzw类似。
min
min dest, src0, src1
dest.x=(src0.x < src1.x) ? src0.x : src1.x;
取较小者,yzw类似。
mov
mov dest, src
拷贝操作,计算方法如下:
if(dest == A0)
{
float p = (float)floor(src.x);
*(int*)&dest.x = FloatToInteger(p);
}
else
{
dest = src;
}
mul
mul dest, src0, src1
dest.x = src0.x * src1.x;
乘法,yzw类似。
rcp
rcp dest, src
取倒数。
rsq
rsq dest, src
取开方后的倒数。
sge
sge dest, src0, src1
dest.x = (src0.x >= src1.x) ? 1.0f : 0.0f;
dest.y = (src0.y >= src1.y) ? 1.0f : 0.0f;
dest.z = (src0.z >= src1.z) ? 1.0f : 0.0f;
dest.w = (src0.w >= src1.w) ? 1.0f : 0.0f;
比较大小。
slt
slt dest, src0, src1
dest.x = (src0.x < src1.x) ? 1.0f : 0.0f;
dest.y = (src0.y < src1.y) ? 1.0f : 0.0f;
dest.z = (src0.z < src1.z) ? 1.0f : 0.0f;
dest.w = (src0.w < src1.w) ? 1.0f : 0.0f;
比较大小。
sub
sub dest, src0, src1
减法计算,dest = src0 - src1。
Macros
exp
frc
log
m3x2
m3x3
m3x4
m4x3
m4x4
我的代码
D3DVSD_STREAM、D3DVSD_REG、D3DVSD_END、D3DVSD_CONST
用于定义各顶点流(Stream)中的数据如何进入v寄存器,详细可参见:Vertex Shader Declarator Macros。
D3DXAssembleShader 从字符串中调入VertexShader代码程序
D3DXAssembleShaderFromFile 从文本文件中调入VertexShader代码程序
D3DXAssembleShaderFromResource 从资源中调入VertexShader代码程序
CreateVertexShader 用于创建VertexShader,
SetVertexShaderConstant 用于设置c寄存器参数,
SetVertexShader 用于设置VertexShader
DeleteVertexShader 用于释放VertexShader
//版本检测**********************************************
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));
//创建VS************************************************
//定义流的格式
LPD3DXBUFFER pCode;
DWORD dwDecl2[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR ),
D3DVSD_END()
};
const char strVertexShader[] =
"vs.1.1 ; Shader version 1.1 \n"\
"m4x4 oPos , v0 , c0 ; \n"\
"mov oT0 , v7 ; \n";
LPD3DXBUFFER ppCompilationErrors;
//从字符串读入VS
if( FAILED( D3DXAssembleShader( strVertexShader, sizeof(strVertexShader)-1, 0,
NULL, &pCode, &ppCompilationErrors ) ) )
{
m_Debug.Add("CCWStaticMesh::D3DXAssembleShaderFromFile Error:\n%s",
(char*)(ppCompilationErrors->GetBufferPointer()));
m_dwVertexShader=0;
return false;
}
//从文件中读入VS
if( FAILED( D3DXAssembleShaderFromFile( strFilename, 0, NULL, &pCode, &ppCompilationErrors ) ) )
{
m_Debug.Add("CCWStaticMesh::D3DXAssembleShaderFromFile Error:\n%s",
(char*)(ppCompilationErrors->GetBufferPointer()));
m_dwVertexShader=0;
return false;
}
//创建VS
if(SUCCEEDED( m_pD3DDevice->CreateVertexShader( dwDecl2,
(DWORD*)pCode->GetBufferPointer(), &m_dwVertexShader, 0 )))
{
m_Debug.Add("CCWStaticMesh::CreateVertexShader OK");
pCode->Release();
return true;
}
else
{
m_Debug.Add("CCWStaticMesh::CreateVertexShader Error");
m_dwVertexShader=0;
return false;
}
//VS渲染*************************************************
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 ); //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 );
//释放VS*************************************************
if(m_dwVertexShader > 0)
{
m_pD3DDevice->DeleteVertexShader(m_dwVertexShader);
m_dwVertexShader = 0;
}
VS代码
1、颜色
float color[4] = {0,1,0,0}; //RGBA
m_pD3DDevice->SetVertexShaderConstant( 4, &color, 1 ); //c4
vs.1.0
m4x4 oPos, v0, c0
mov oD0, c4
2、纹理
vs.1.0
m4x4 oPos, v0, c0
mov oT0, v7
3、光照
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
设置c寄存器的三种方法
有孔乙己老兄的回字四种写法之嫌,不管怎么样,折腾了半天总算搞清楚了,故记之。
1、SetVertexShaderConstant函数,最简单最直接的,方便动态修改,就用这个好了,下面的两种方法可以跳过。-_-
2、D3DVSD_CONST的宏定义,在流格式定义时写入,例子:
float diffuse[] = {1, 1, 1.0f/255.0f, 1};
DWORD decl[] =
{
D3DVSD_CONST(8, 1),
*(DWORD*)&diffuse[0],*(DWORD*)&diffuse[1],*(DWORD*)&diffuse[2],*(DWORD*)&diffuse[3],
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_NORMAL , D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
D3DVSD_END()
};
这样就将diffuse定义的四个float写到了c8里面,每次SetVertexShader的时候会自动载入所定义的c寄存器,注:可在SetVertexShader后再调用SetVertexShaderConstant来修改c寄存器。
3、在vs代码中用使用def指令定义c寄存器,然后在D3DXAssembleShader函数、D3DXAssembleShaderFromFile函数或者D3DXAssembleShaderFromResource函数调用时取得编译好的c寄存器定义代码,加入到流格式定义中,然后使用和方法2相同的形式调用之。本以为这个应该是最简单的方法,谁知道却是最麻烦的,始终没搞明白c寄存器为什么对VS指令是只读的,而非要用外部代码来写入,代码如下:
vs.1.1
def c9, 0.0f,1.0f,0.1f,1.0f
m4x4 oPos, v0,c0
add oT0, v7,c9.z
LPD3DXBUFFER pCode;
DWORD dwDecl1[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_NORMAL , D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2 )
};
DWORD dwDecl3[] =
{
D3DVSD_END()
};
// Assemble the vertex shader from the file.
LPD3DXBUFFER ppConctant;
LPD3DXBUFFER ppCompilationErrors;
if( FAILED( D3DXAssembleShaderFromFile( a_strFilename, 0, &ppConctant, &pCode, &ppCompilationErrors ) ) )
{
m_Debug.Add("D3DXAssembleShaderFromFile Error:\n%s",(char*)(ppCompilationErrors->GetBufferPointer()));
m_dwVertexShader=0;
return false;
}
int SizeOfDW;
BYTE pDeclAll[1024];
SizeOfDW=sizeof(dwDecl1);
memcpy(pDeclAll,dwDecl1,SizeOfDW);
memcpy(pDeclAll+SizeOfDW,ppConctant->GetBufferPointer(),ppConctant->GetBufferSize());
SizeOfDW+=ppConctant->GetBufferSize();
memcpy(pDeclAll+SizeOfDW,dwDecl3,sizeof(dwDecl3));
// Create the vertex shader.
if(SUCCEEDED( m_pD3DDevice->CreateVertexShader( (DWORD*)pDeclAll,
(DWORD*)pCode->GetBufferPointer(), &m_dwVertexShader, 0 )))
{
m_Debug.Add("CreateVertexShader OK");
pCode->Release();
return true;
}
else
{
m_Debug.Add("CreateVertexShader Error");
m_dwVertexShader=0;
return false;
}
coolvoldo
2003.10.01.12:00,build10 |
|