这个Effects Browser是一款很棒的测试和开发顶点和像素着色器的工具。你可以选择你喜欢看的效果在左边圆柱。中间给你可能的看到顶点来源或像素着色器。正确的圆柱显示效果。
不是所有的图形卡都支持Effect Browser里的效果。 GeForce3/4TI将支持所有的效果。在你当前图形卡偏爱独立的,我推荐你下载NVIDIA的DirectX 8 SDK和试图。有许多例子,包括解释细节,展示给你使用顶点和像素着色器变化的效果。即将来临的NVIDIA效果浏览器3将提供自动在线更新能力。
顶点着色器体系
让我们更深入的获取图形信息看下顶点着色器的体系:
寄存器(128bits == 4floats 12 entries)->Vertex Input(128bits == 4floats 16entries)
->VertexShader 128 instructions -> VertexOutput(128bits == 4 floats 13entries)- ->
Constant Memory(128bits == 4floats 96entries RADEON 8500: 192entries)
顶点着色起上所有数据都用128bit四维-floats(4x32bit):
x y z w
一贯件顶点着色器已经被典型的SIMD(Single Instruction Multiple Data)处理器,作为你应用一个指令和影响到4个32bit变量的设置。数据格式非常有用因为大部分变换和关照计算使用4x4矩阵或四元组执行。指令非常简单和容易理解。顶点着色器不允许任何循环,跳转,或者条件分支,这意味着它执行起来是线性程序-一个接一个。DirectX 8.x最大的顶点着色器程序指令长度为128指令。整合顶点着色器到有计算转换和另一个计算光照难以忍受的。仅仅一个顶点着色器在一次可以被激活,而且活动的顶点着色器械=必须所有请求每个顶点输出数据。
所有顶点着色器使用16个输入积存器(命名为v0-v15,每个寄存器由128bit(4x32)quad-floats)组成用于存取顶点输入数据。顶点输入寄存器可以容易的从电点顶点获取数据:位置坐标,法线,扩散和反射颜色,雾坐标,和点大小信息为坐标多个纹理。
常量寄存器(常量内存)被在顶点着色器启动执行前通过CPU加载由程序员定义。顶点着色器不可以写常量寄存器。他们被使用存储程序员像光位置,矩阵,程序上的特殊动画效果,顶点插补数据为morphing/关键帧interpolation,更多。常量可以不使用程序,而且甚至被间接的定位地址使用地址寄存器(a0.x,但是每条指令仅仅可以使用一个常量。如果一个指令需要更多的常量,它必须加载一个在被请求之前被加载到临时的寄存器中。常量寄存器从c0-c95,在ATI RADEON 8500,c0-c191.
临时积存器由12个寄存器计算媒体组成。它们可以被用来加载数据和存储数据(读/写).临时寄存器被r0-r11.
顶点输出寄存器有13,依赖于硬件。输出寄存器总用于输出。输出寄存器也可以每个执行光栅,你的顶点着色器程序已经仅仅访问它。最后结果也被另一个顶点执行,顶点变换到同质的裁剪空间。下表是一个所有可用到的寄存器的表。
Input(v0-v15) 16 RO1
Output(o*) GetForce 3/4TI: 9; RADEON 8500: 11 WO
Consants(c0c=-c95) vs.1.1 Specification: 96; RADEON 8500: 192 RO1
Temporary(r0-r11) 12 R1W3
Adress(a0.x) 1(vs.1.1 and higher) WO(W: only with mov)
在输出寄存流自然是顶点着色器标识符只读的和输出寄存器是可写的。
高级视图的顶点着色器程序
每次仅仅可以激活一个顶点着色器。在每个基础任务上更好想法是写顶点着色器。在不同的着色器之间切换是很小消耗的,例如,纹理改变。所以如果对象需要特殊的几何或光照呢,它将获取适当的着色器信息。让我们构造一个抽象的例子:
你可以遭遇外部的行星。在正规马甲外穿女衣服仅仅使用jigsaw,you move through the candlelit cellars.一个怪物允许,你蜷缩在那些柳条箱里一个正常的找到其他行星。同时思考你的命运是英雄保存jigsaws,你启动计算在这个场景里的几个顶点着色器。
有一个或更多妖怪动画,光,也许反射它的环境。其他的顶点着色器将被用在地板,墙壁,箱子,摄影机,烛光和你的jigsaw.也许地板什么用同样的着色器,但是烛光和摄影机用它们自己的。这依赖于你的设计和图形卡硬件的强大。
注意:你也许使用顶点着色器在每个对象或者每个mesh基础。如果,例如,一个*.md3模型组成,我们说10个meshes,你可以执行10个不同的顶点着色器,但是也许损害你的游戏性能。
每个顶点着色器驱动程序必须运行使用下面的步骤:
检测D3DCAPS8::VertexShaderVersion检测顶点着色器的支持情况。
使用D3DVSD_*宏定义影射顶点缓冲流到输入寄存器
使用SetVertexShaderConstant()设置常量寄存器
当顶点着色器使用D3DXAssembleShader*()(这个预编译程序汇编)写在顶点着色器
使用CreateVertexShader()创建顶点着色器句柄
使用SetVertexShader()指定顶点着色器对象
使用DeleteVertexShader()删除顶点着色器。
检测顶点着色器版本支持
检测用户是否安装顶点着色器的软件或硬件实现是重要的。如果缺乏指定特性的支持,然后应用程序可以要求命令。下面的语句检测顶点着色器版本1.1:
if(pCaps->VertexShaderVersion < D3DVS_VERSION(1,1))
return E_FAIL;
下面的语句检测顶点着色器版本1.0:
if(pCaps->VertexShaderVersion < D3DVS_VERSION(1,0))
return E_FAIL;
D3DCPAS8结构必须调用GetDeviceCaps()函数来跳虫。如果你使用公共文件框架提供的DirectX 8.1 SDK,框架将帮你完成。如果你的图形硬件不支持你的顶点着色器版本,你必须使用D3DCREATE_SOFTWARE_VERTEXPROCESSING标志在CreateDevice()调用软件顶点着色器。先前提及的
优化软件实现在Intel和AMD提供它们的各自的CPUs将处理顶点着色器。
支持的顶点着色器版本:
Version
0.0 DirectX 7
1.0 DirectX 8 without addresss register a0
1.1 Direct 8 and DirectX 8.1 with one addresss register a0
2.0 DirectX 9
在1.0和1.1之间仅仅是a0寄存器的支持的不同。DirectX 8.0和DirectX 8.1引用光栅线和软件模拟设备被Intel和AMD它们各自的CPU支持1.1.在时间发布上,仅仅GeForce3/4TI和RADEON 8500驱动板卡在硬件上支持1.1.不知道仅仅支持vs 1.0的图形卡出版没有,所以是遗留下来的版本。
顶点着色器定义
你必须在使用顶点着色器之前定义它。这个定义可以叫做静态外部接口。一个例子也许是这样的:
float c[4] = {0.0f,0.5f,1.0f,2.0f};
DWORD dwDecl0[] - {
D3DVSD_STREAM(0),
D3DVSD_REG(0,D3DVSDT_FLOAT3),
D3DVSD_REG(5, D3DVSDT_D3DCOLOR),
D3DVSD_CONST(0,1),*(DWORD*)&c[0],*(DWORD*)&c[1],*(DWORD*)&c[2],*(DWORD*)&c[3],D3DVSD_END()
);
顶点着色器械定义设置数据流0使用D3DVSD_STREAM(0).之后,使用这个定义设置绑定到流的源
SetStreamSource().你可以引入不同的Direct3D流来渲染引擎。
注意: 例如,数据流可以控制位置和法线,同时第二个控制颜色值和纹理坐标。这也在单个纹理渲染和多纹理渲染产生不同的方式:使用第二个设置纹理坐标开启流。
你必须定义输入顶点属性或引入的顶点数据有输入寄存器的映射。D3DVSD_REG帮定单个顶点寄存器到顶点元素/属性从顶点流。在这个例子,一个D3DVSDT_FLOAT3值将被放在第一个输入寄存器,和D3DVSDT_D3DCOLOR颜色值将被放在六个输入寄存器。例如,位置数据将被输入寄存器使用D3DVSD_REG(0,D3DVSDT_FLOAT3)和法线数据压缩,可以被处理到输入寄存器3(v3)使用D3DVSD_REG(3,D3DVSDT_FLOAT3).
开发者绘制地图每个输入顶点属性到指定输入寄存器是仅仅重要的如果一个人想获得N-Patches音问N-Patch tessellator需要在v0和在v3法线数据。另外,开发者自由定义作为看发作映射。例如,位置数据将被输入寄存器0(v0)用D3DVSD_REG(0,D3DVSDT_FLOAT3),和法线数据将被输入寄存器3(v3_使用D3DVSD_REG(3,D3DVSDT_FLOAT3).
注意:对比,映射顶点数据输入指定寄存器是使用固定的函数管线 d3d8types.h有列表#defines那个预先确定顶点输入固定函数管线。指定顶点元素像位置或法线必须在指定寄存器的顶点输入内存位置。例如,顶点位置在D3DVSDE_POSITION到寄存器0,发散颜色是围绕D3DVSDE_DIFFUSE到寄存器5,等。这里完成从d3dtypes.h列表。
第二个参数D3DVSD_REG指定在维度和算法数据类型。下面的值被定义在d3d8types.h:
注意: GeForce3/4TI不支持D3DVSDT_UBYTE4,作为显示在D3DVTXPCAPS_NO_VSDT_UBYTE4 caps位。
D3DVSD_CONST加载常量值在顶点着色器常量内存。第一个参数在其实地址填充常量数组。可能的值范围从0-95或者,在RADEON 8500情况,从0-191.我们从0地址开始。第二个数值是从常量响亮(quad-float)被加载。一个向量是128位长,所以我们加载4个32bit浮点一次。如果你想加载4x4矩阵,你将使用下面语句加载为4个128bit quad-flaots到常量寄存器c0-c3:
D3DVSD_END产生结束符号到标记在顶点着色器定义。另外的例子是:
数据流被设置使用D3DVSD_STREAM(0).顶点位置(值,值,值,1.0)也许被发现在v0,法线值也许被发现v3,发散颜色也许在v5范围,和纹理坐标(值,值,0.0,1.0)也许被发现到v7.常量寄存器c0获取一个128bit的值。
设置顶点着色器常量寄存器
你将填充着色器使用SetVertexConstant()和使用GetVertexShaderConstant():从这些寄存器获取值:
SetVertexShaderConstant()被作为定义:
HRESULT SetVertexShaderConstant(DWORD Register,CONST Register,CONST void* pConstantData,DWORD ConstantCount);
作为状态初期,有至少96个常量寄存器(RADEON 8500有192)比可以用四个浮点值在顶点被执行前填充。第一个参数有加载数据到顶点常量数组。最后一个参数握有常量值(4x32位值)加载到顶点常量数组。所以在第一行以上,vZero将被加载到寄存器0,matTranspose将北加载到寄存器超过7,matViewTranspose将被加载到寄存器12超过15,寄存器16超过19没有被使用,fLight被加载到寄存器20,和寄存器25超过27被使用。
注意:suoyi zai D3DVSD_CONST使用顶点着色器不同定义和SetVertexShaderConstant() D3DVSD_CONST可以被仅仅一个使用,同时SetVertexShaderConstant()可以在DrawPrimitive()前被加载。
我们有学到怎样检测值顶点着色器的硬件版本,怎样定义和怎样在顶点着色器单元定义常量单元。下一个我们将学习怎样写和编译顶点着色器程序。
写和编写顶点着色器
在我们可以编译顶点着色器前,我们必须写。我们喜欢使用高级视图指令进行最初的设置和然后给未来在下篇文章进行顶点着色器编程,‘顶点着色器编程“。
语法每个指令像这样:
OpName dest,[-]s1,[,[-]s2,[,[-],s3]];comment
e.g.
mov r1,r2;
mad r1,r2,-r3,r4; contents of r3 are negated
你可以下载列表从www.shaderx.com。检测SDK附加的信息。
顶点着色器ALU被多线程向量处理器进行操作在quad-float数据。它包含两个函数单元。SIMD向量单元可依赖的mov,mul,add,mad,dp3,dst,min,max,slt,和sge指令。特殊的指令单元如rcp,rsq,logp,expp,和lit指令。大部分这些指令有一个执行周期,虽然rcp和rsq执行少于下面指定的状况的周期。它们仅仅在跟踪顶点着色器,但是它们实际上很长周期当结果使用只的因为开启寄存器延迟。
应用线索
rsq,例如,使用规格化响亮在光比较。可说明的expp可以被雾效果,程序上的产生糟点(看NVIDIA花边糟点例子在同伴CD),例子举止行为在例子系统上(看NVIDIA里子系统在同伴CD上),或者在实现系统怎样的对象在游戏中损害。你将使用它当快速改变函数是必要的。这个相反的使用对数函数使用logp,哪里是有用的如果极端的慢增长必要的(也它们增长漂亮快速在开始).在航行日志在函数可以在反转的支书函数,意味这它取消指数函数的操作的。
光质量处理默认使用直射光。它计算发散和反射光使用夹注基于在N*L和N*H在反射能力上。没有变薄,但是你可以使用衰减等级分别的使用dst指令产生结果。这对于构造稀释的因素为点和聚光灯是必要的。大的小的指令允许夹住和完全的计算值。
顶点着色器中的复杂指令
顶点着色器中也有复杂的指令支持。术语"macro"将被在这些指令中使用,因为它们不像简单的C-预处理器中的宏。在使用这些指令前,你应该仔细想想。如果你使用它们,你也许遗失控制你的有限的128bit指令优化路径。另一方面,软件模拟模式提供在Intel 或AMD可能的m4x4复杂指令的优化(也许其他或者在未来支持).也可能在未来,一些图形硬件也许使用大门计算和最优化的m4x4.所以,如果你需要,例如,4个dp4在你的顶点着色器被汇编源代码调用,它也许被高的思想取代它们m4x4.如果你决定使用一个m4x4指令在你的着色器,你将不可以使用dp4调用之后相同的数据因为有些微笑的转换结果的不同。如果,例如,计算位置的双指令,z-光照将是这样的结果:
Macro Parameters Action Clocks
expp frc log m3x2 m3x3 m3x4 m4x3 m4x4
你可以执行所有的变换和光照指令使用这些指令。如果它看起来像在你的一些指令缺少,休息保证在你可以完成它们通过存在的指令。例如,分开的两个成员可以实现使用响应的和增加。你甚至可以实现在顶点着色器中所有的固定函数。这里展示了NVLink例子在同伴CD上。
进行所有的设置
现在让我们看这些寄存器和典型的使用顶点着色器ALU.
在vs.1.1,有16个输入寄存器,96个常量寄存器,12临时寄存器,1地址寄存器,和向上的13个输出寄存器没光栅化。每个寄存器持有4x32bit值。每32bit位值是可理解的经过x,y,z,和w写在下放。换句话说,一个128bit值有x,y,z,w值组成。访问这些寄存器组件,你必须添加x,y,z,w在寄存器名字结束。让开始输入寄存器。
使用输入寄存器
16个输入寄存器被使用它们的名字进行访问v0-v15.典型的值提供输入顶点寄存器是:
位置(x,y,z,w)
发散颜色(r,g,b,a) - 0.0 到 + 1.0
反射颜色(r,g,b,a) - 0.0到 +1.0
向上到8个纹理坐标(每个作为s,t,r,q或u,v,w,q)但有四个或6个是规格化的,以来在硬件的支持
雾(f,*,*,*)-值在使用雾平衡
点大小(p,*,*,*)
你可以访问x-组件使用v0.x值,y-组件使用v0.y,等。如果你需要知道RGBA发散颜色组件,你检测v1.y.你也许设置雾值,例如,设置v7.x.其他三个32bit组件,v7.y,v7.z,和v7.w,将不被使用。输入寄存器被设为只读。每个指令也许仅仅访问顶点寄存器。不指定输入寄存器组件默认0.0到x,y,和z组件和到1.0为w组件。在下面的例子,4个组件点乘积在每c0-c3之间和v0被存储在oPos:
dp4 oPos.x,v0,c0
dp4 oPos.y,v0,c1
dp4 oPos.z,v0,c2
dp4 oPos.w,v0,c3
像代码片段通常设置从发射空间到裁减空间使用已经凹面的世界,视图和发射矩阵。下面的四组点乘:
oPos.x - (v0.x * c0.x) + (v0.y * c0.y) + (v0.z * c0.z) + (v0.w * c0.w)
给我们使用长度单元(规格化)向量,它点乘两个向量将总在范围[-1,1]。因此,oPos将总被获取值在这个范围内。二选一的,你将使用:
m4x4 oPos,v0,c0
不要忘记使用这些复杂指令一向经过你的顶点着色器因为被过早的讨论,这也许被在dp4和m4x4结果有些不同。你将限制仅仅使用输入寄存器在每个指令。
所有数据在输入寄存器仍然持久稳定通过顶点着色器执行和甚至比较。这意味者它们仍然在顶点着色器的生存器内比较。所以他可以再使用输入数据在下个顶点着色器。
使用常量寄存器
典型的使用常量寄存器包括:
矩阵类型-quad-floats是典型的4x4矩阵的行
光描述(位置,衰减等)
当前时间
顶点interpolation数据
程序上数据
有96个quad-floats(或着RADEON 8500,192quad-floats)提供存储常量数据。这个原因大的色绘制矩阵可以被使用,例如,顶点索引混合知道(矩阵角色调色板."
常量寄存器被从透视顶点着色器是只读的,然而应用可以被读和写信到常量寄存器中。常量寄存器仍然在它们的数据不再顶点着色器的生存器内,所以它重新使用这些数据在下个顶点着色器。这允许app避免多余的设置SetVertexShaderConstant()调用。从范围外读常量寄存器返回(0.0,0.0,0.0,0.0).
你将使用仅仅一个常量寄存器每个指令,但是你将使用它许多次。例如:
mul r5,c11,c11;
add v0,c4,c3
更多的复杂查看,但是有效的,例如:
mad r0,r0,c20,c20;
使用地址寄存器
你访问地址寄存器使用a0到an(更多的地址寄存器将可用到在顶点着色器版本比1.1高).在vs.1.1仅仅使用一个间接地址操作偏离常量内存。
c(a0.x + n);
这里一个使用地址寄存器的例子:
mov a0.x,r1.x
m4x3 r4,v0,c[a0.x + 9];
m3x3 r5,v3,c[a0.x + 9];
依赖在临时寄存器r1.x中存储的值,不同的常量寄存器被在m4x3和m3x3指令中使用。请注意寄存器a0仅仅存储同时数据和没有分数(仅仅整数)和a0.x是仅仅有效的组件a0.更远的,一个顶点着色器也许写到a0.x仅仅经过mov指令。
注意:小心a0.x如果有仅仅软件模拟模式;执行可以被意味深长的可以引出[Pallister].
使用临时寄存器
你可以使用12个临时寄存器使用r0-r11.这里有些例子:
dp3 r2,r1,-c4
mov r0.x,v0.x
mov r0.y, c4.w
mov r0.z,v0.y
mov r0.w,c4.w
每个临时寄存器有单个写和三倍的读访问。因此,一个指令有相同的临时寄存器作为源三次。顶点着色器在写之前不能读取里面的值。如果你试着读取临时寄存器不能使用值,API将给你一个错误信息创建顶点着色器。
使用输出寄存器
有向上到13仅仅写输出寄存器比可以被访问使用下面寄存器名字。它们被定义作为输入在光栅化,每个寄存器被用小写字母处理"o".输出寄存器被命名为建议他们使用像素着色器。
oDn oPos oTn oPts.x oFog.x
这里一个典型的例子将战士怎样使用oPos,oD0,和oT0寄存器:
dp4 oPos.x,v0,c4
dp4 oPos.y,v0,c5
dp4 oPos.z,v0,c6
dp4 oPos.w,v0,c7
mov oD0,v5
mov oT0,v2
使用4个dp4指令映射从发射裁减空间已经转道凹面世界,视图和投影矩阵被展示下。首先mov指令移动在v5输入寄存器到颜色输出寄存器,和第二个mov指令移动到值v2寄存器到输出到纹理寄存器。
使用oFog.x输出寄存器被展示在下面的例子里:
dp4 r2,v0,c2
sge r3,c0,c0
add r2,r2,-c5.x
mad r3.x,-r2.x,c5.z,r3.x
max oFog.x,c5.w,r3.x
有一个雾值许可更多普通的雾效果比使用z的位置或w值。雾距离在插补使用距离在标准雾方程使用管线后。 |