编者按:这篇文章成文于2004年4月19日,发表在《大众硬件》杂志上。虽然现在Vista已经发布快半年了多了,但是DX10的游戏还一个都没有出来,目前所有新游戏仅仅支持DX9。可见Shader Model 3.0还是在最鼎盛得时期。这篇文章就从深刻的技术层面剖析了Shader Model 3.0的许多先进特性。绝对是一篇充电牛文,推荐大家阅读。
力量源泉——Shader 3.0揭密
近来,随着ATI和NVIDIA下一代显示芯片的细节参数浮出水面,全世界的3D游戏玩家又开始狂热起来。每一个人都在翘首企盼着业界两大显示芯片的设计巨人能够尽早发布这具有跨时代意义的显卡。在各位玩家想破脑袋来猜测下一代显示卡中的一些特色技术的时候,我们不禁要思考一个问题:从Shader 2.0到Shader 3.0的升级过程中,微软究竟给我们带来了哪些新的技术?
当然如果你想知道全部的答案的话你需要等待相当长的一段时间。只有亲手玩到游戏开发人员的游戏之后,你才能真正的体会到他们之间的不同。虽然这些实现的技术细节也是相当专业和枯燥的,但是这并不是说我们没有机会诠释未来的Shader 3.0中的很多特性。我们还是可以来研究一下未来Shader 3.0具备的一些基本功能。未来的Shader 3.0让显示芯片充分发挥运算效能,演艺出完美的画质。在这篇文章中会给你描述出下一代Shader的一个基本的轮廓。
Pixel Shader 3.0(象素着色引擎)
若拿Pixel Shader 3.0与2.0相比,前者的复杂程度要远远高于后者。在Pixel Shader 2.0中共有两种指令集合。一个是微软官方在DircetX9中所制定的最为基本的Pixel Shader标准指令集。另一个是各大图形芯片厂商为了提高自己的产品竞争力和处理的效能而提出的Pixel Shader扩展指令集。例如NVIDIA在GeForce FX中所使用的就是这种扩展指令集。在这两种Pixel Shader标准和扩展指令集中,存在着很多的差异。你可以从下面的表格中清楚的了解到各个版本的Pixel Shader中的指令集的差别。
版本
|
最小指令个数
|
最大的指令个数
|
1.1
|
8
|
8
|
1.2 / 1.3
|
12
|
12
|
1.4
|
14
|
14
|
2.0
|
64数值计算,32 材质计算
|
64数值计算,32 材质计算
|
2.0 延伸
|
96
|
512
|
3.0
|
512
|
32,768
|
你可以通过上面的表格了解到整个Pixel Shader的发展历程。你可以看出Pixel Shader在1.x的发展阶段是非常缓慢的。到了Pixel Shader 2.0阶段,指令集的处理个数就大大增加了。在2.0的扩展版本中最大指令集增大到了512个。而到了Pixel Shader 3.0的时候,最小指令集已经是2.0扩展版本的最大指令数了。看来整个Pixel Shader发展的历程是处理指令的个数的积增。然而在Pixel Shader 3.0中GPU要同时处理如此众多的指令集,那么它的处理效率就成为了人们一直争论的话题。我们尚且先不考虑硬件的实现可能性。游戏开发人员可以使用如此众多的象素着色指令的确会增大3D游戏程序的弹性。
事情还远远没有这样简单。ps_2_b profile是微软在DircetX9 HLSL(高级Shader语言)中加入的一个功能插件。它的出现给Pixel Shader 2.0带来了许多强大的功能。但是它并没能够充足的使用Pixel Shader 2.0扩展版本的512条指令集。根据我们的猜测,由于R420系列不支持真正意义上的Pixel Shader 3.0,微软才专门为了R420开发出这种profile功能扩展包,用来增强硬件的可用性。相信随着DircetX新版本的推出,会有更多的profile包出现。另外还有一点值得注意的是,最小指令数量定义了硬件可以适应于Shader 模型的指令所需的最小指令处理数量,而不是一个Shader程序所必须用的最少的指令数。简单的几何构图是不必采用复杂的Shader指令。
我们现在结束对Shader指令个数的讨论,再来看看Pixel Shader 3.0究竟给我们提供了什么新的特性。以一个游戏玩家的角度来看,在Pixel Shader 3.0中并没有加入什么提高游戏画面质量的特殊功能。更多的改进是为了游戏开发人员能够更为便捷的开发游戏,让游戏程序更具备弹性,使开发人员写出更为强大的程序。事实上,在Pixel Shader 3.0中沿用了很多2.0扩展版本的一些规范,现在Pixel Shader 3.0的标准版本中就可以直接使用这些规范。在我们更进一步的讨论这些细节之前,让我们先来看看微软官方在Pixel Shader 3.0中都加入了哪些主要的特性:
静态和动态流控制(Static and dynamic flow control )
重复数据预测(Predication )
动态分支(Dynamic branching )
允许使用新型的寄存器,和使用更多的寄存器(New registers, and more temporary register usage allowed )
新型的梯度/材质指令(New gradient/texture instructions)
质心采样(Centroid sampling )
任意羼合(Arbitrary swizzle )
动态流程控制和动态分支
在去年GeForceFX发布的时候有一个词被炒的很热,那就是动态流程控制。它属于Pixel Shader 2.0扩展版中的一项独特的技术。在Pixel Shader 3.0的规范推出之后这项技术更值得我们关注了。这种动态的流程控制,本质上讲是一种提高Shader指令执行效能的方法。理论上来说,它可以防止很多不必要的Shader指令被执行。它可以过滤那些不必要的指令请求,使GPU能够有更多的时间去处理更重要的Shader指令。它也可以使程序更加多样和灵活。使游戏开发人员能更方便的控制程序的流程作业。
动态分支与上述的动态流程控制相似,它大大扩大了Shader程序的应用范围。从而改进整个计算机对于大量3D数据的处理效能。举一个简单的例子,假如游戏开发人员想在游戏中加入许多条光线,并且使用Shader来处理这些光线。那么在传统的做法中,游戏开发人员要为每一条光线编写渲染程序。那么如果使用动态分支的方法来编写程序,游戏开发人员仅仅需要编写一条光线的渲染程序。然后只要说明还有哪些同样的光线,在屏幕的哪些位置出现即可。很明显这会大量减少游戏程序的开发时间。并且也会大大增加GPU的处理效率。
不过目前业界的游戏开发人员对于动态分支的技术也产生出了两种对立的流派。其中一派认为,动态分支技术可以极大的提高系统的处理效能,这是一个非常实用的方法。而另一派认为,动态分支在某些显示芯片的渲染管道中所表现出来的性能提升并不是十分明显。他们认为在分支设计思想中对数据处理的方法并不合理。玩家最后能在屏幕上看到许多条光线,但是这些光线都一模一样,游戏兴趣将大打折扣。不过现在这两种说法似乎都缺乏足够的依据。
质心采样
也许从今年的夏天开始,所有最发烧的3D游戏玩家的嘴边都会经常提起这样一个非常专业的词汇——质心采样。细心的玩家也许会记得,Valve公司的“Shader纪念日”。Valve宣称只有ATI的显卡才能真正支持Half-Life 2中特殊开发的最新全屏反锯齿技术。因为ATI的R360显示芯片在硬件级别上支持质心采样技术。然而,NVIDIA的GeForceFX系列的显卡则不支持这项技术。随着时间的流逝R420和NV40已经发布,曾经的Valve的独门全屏反锯齿技术现在已经可以同时在ATI和NVIDIA的显卡上实现。并且Valve的技术垄断也慢慢被打破,也会有越来越多的游戏开发公司宣布支持这一先进的特效技术。所有的3D玩家已经不必等待,现在质心采样这项技术已经直接可以在Pixel Shader 3.0的函数库中调用,通过DircetX9.0c即可在游戏中实现。
那么质心采样技术究竟是什么呢?首先我们要看一看Valve在开发Half-Life 2时所遇到的一些困难。游戏的开发人员可以利用传统的多重采样全屏反锯齿技术(multisample antialiasing)对象素的中心进行采样。在使用某些特殊的贴图效果时(例如使用特殊的光照贴图)系统由于不能辨别是材质的原始数据,还是渲染之后的特殊光照贴图而无法对象素进行多重采样处理。在使用全屏反锯齿的游戏的场景中,我们就会发现大量的贴图错误。这个问题事实上也同样困扰着许多其他的游戏开发人员。如果你细致的观察那些打开了多重采样反锯齿的游戏画面,场景都会或多或少的出现贴图错误。
质心采样就可以很好的解决这一问题。它可以确认所进行多重采样时的数据都是三角形表面的原始材质数据。这样就能让所要处理的材质数据永远都是正确的,避免了材质数据采样时的冲突。
重复数据预测
重复数据预测与动态流程控制/动态分支有着非常紧密的联系。这些新的特性都是用来加强GPU对于Shader的指令执行效率。事实上这种重复数据预测技术很早以前就被用于大型数据库的设计中。它是利用历史数据找出变化规律、建立模型,并由此模型对未来数据的种类及特征进行预测。预测过程中最关键的是精度和不确定性。而在Pixel Shader 3.0中的重复数据预测技术可以使GPU更好的处理繁多的数据块操作请求。它可使GPU能够更好的预测数据块的处理过程。最后仅仅将预测正确的数据发送给GPU的处理管线。尽管对这些重复数据的预测和分析都会花费大量的处理时间,但是这总比盲目的使用随机函数来猜测数据块的结果显得更有效率。重复数据预测与动态分支技术一样,也遭到了很多人的质疑。虽然它可使GPU的工作效率更高,但是最后的预测结果仍然需要花费大量的时钟周期去校对。
任意羼合
任意羼合并不是Pixel Shader 3.0版本中新加入的特色功能,早在2.0时代就已经浮现出它的身影了。任意羼合可以看作是一个“修改器”,它用于修改指令和寄存器内的参数。通过它系统不必直接执行Shader指令,就可修改材质和象素的一些数据。这样在GPU处理3D数据的时候,就可以大量减少使用Shader指令的数目,从而提高系统的处理效能。以前在Pixel Shader 2.0版本中,支持的羼合指令非常有限。程序员只能对指令合寄存器内的某些特定的参数,作一些非常有限的操作。例如仅仅能对数据进行加法、减法等数学运算。而在最新的Pixel Shader 3.0版本中,程序员除了可以对数据进行数学计算之外,甚至还可以对数据进行逻辑计算。比如,在处理某一个游戏场景的时候,需要频繁的对寄存器内的材质数据进行“移动”指令的操作。现在的3.0版本中的羼合就完全支持材质数据的移动。这样GPU就可以使用执行速度更快,更为便捷的羼合指令来完成数据的处理任务了。
Vertex Shader 3.0
首先还是让我们先来看一看各个版本中的Vertex Shader中,能够处理指令的最大数量。见表格。
Vertex Shader
版本
|
最大指示数
|
1.1
|
128
|
2.0
|
256
|
2.0 扩展
|
256 (使用循环语句时可以更高)
|
3.0
|
512
|
如你所见,Vertex Shader从2.0版本的最大256条增加到了3.0版本的512条。并且在微软的DircetX9的详述规范中特别指出,512仅仅是Shader 3.0硬件标准的下限。图形芯片设计厂商可以在这个基础上任意发挥。
下面我们来看一看Vertex Shader 3.0中的一些主要的新特性:
静态和动态流控制(Static and dynamic flow control )
重复数据预测(Predication )
动态分支(Dynamic branching )
指数寄存器,和使用更多的寄存器(Indexing registers, and more temporary register usage allowed)
顶点材质调用(Vertex textures)
顶点数据流周期(Vertex stream frequency)
在Vertex Shader和Pixel Shader中有很多都是共通的东西,比如静态和动态流控制和重复数据预测等等。这些技术的实现方式大致相当,上文的Pixel Shader中我们已经介绍过,因此这里就不再熬述。
顶点材质
顶点材质的实现原理其实相当简单。在过去,Vertex Shader的顶点运算单元无法直接访问显存中的材质数据。他们必须向显示芯片发出请求,交由Pixel Shader来完成所有的材质处理任务。现在这种繁琐的工序得以改观。Vertex Shader顶点运算单元可以直接检索显存中的材质数据。现在的游戏场景越来越复杂了。所涉及到的材质和多边形数量都非常惊人。顶点材质技术可以极大的提高GPU在处理复杂的游戏场景时的效率。并且游戏开发人员还可以利用Vertex Shader的这一新的特性,充分发挥想象,实现很多非常漂亮的特效。
顶点材质技术最为显著的受益者莫过于置换贴图了(Displacement mapping)。置换贴图在去年曾经被各大媒体炒的很热,它是DircetX9中一项高级的贴图技术。由于上一代图形显示芯片设计的并不是非常成熟,在硬件上造成许多限制。这使得置换贴图在游戏中的实际效果并不太让人满意。例如在Matrox出品的Parhelia显示芯片中,在每个调用的过程中,置换贴图的程序需要预先就被创建好。而在新的Vertex Shader 3.0中所有的置换贴图过程都是可编程的,游戏可以根据场景和玩家的操作交互的生成置换贴图。这样书写的程序更为便捷更为灵活。
顶点材质的另一个好处是,当Vertex Shader顶点运算单元具备读取材质数据的时候它就可以创造出更接近自然的物理运动仿真。Vertex Shader可以模拟出相应的物理效果,并且把结果以几何的形式输出到显示器上。游戏开发人员可以使用这种“材质数据+Vertex Shader”的新模式来创造出现实世界中很多独特对象的质感。比如创造出更真实的水滴物理运动,使平面贴图更接近麻布的质感等等。
顶点数据流
在Shader 3.0中,顶点数据被分割成不同比特率的数据流。游戏开发人员使用这些顶点数据的数据流可以创造出更生动的特效画面。一般来说,在以前的Vertex Shader数据模型中,每个时钟周期都要调用同等容量的顶点数据,然后所有的顶点数据寄存器才会被初始化。在3.0版本中这些输入的数据流可以选用不同的速率。也就是说传送到GPU内的顶点数据,是可以随着游戏场景的复杂程度而相应的发生变化的。低速率的数据流仅仅涵盖基本顶点位置等粗糙数据,它应用在那些简单的几何构图和没有特殊效果的画面中。而高速率的数据流除了包括基本顶点位置数据之外,还包括顶点的相对变化,特殊效果指令等数据。使用这种新的顶点数据流,应用程序的寄存器在空闲的时候调用顶点数据的数据量将大大下降,从而它可以大大节省显示芯片的工作量,提高了显示芯片的工作效率。
由于顶点数据改用数据流的形式传送,内部的顶点数据传输总线也可以支持很大的突发数据传输速率。这样显示芯片可以更从容的处理那些突发的大规模场景特效。(许多华丽的3D特效都需要很大的运算量,例如下雨,爆炸,粒子喷发等等)在顶点数据流的传输过程中,也扩充了多种数据类型。这可以使得游戏开发人员更详细的对一个顶点进行描述。
顶点数据流的另一个好处就是,一个经过运算之后的顶点缓存数据可以反复再进行若干次的循环调用,这样就可以通过一个相同物体的基本范例创造超过驱动程序限制的对象。例如,游戏开发人员若要创造一个森林的场景可以首先使用低比率的数据流构建一棵树的基本框架。然后再用高比率的数据流包含每一棵真实的树木特征模型,这包括树叶的模型,树枝的模型,树干的模型等等。将整个一棵树定义成一个元素。最后再使用基于低比率数据流中的元素ID,循环处理生成整个广茂的森林。
对于游戏玩家来说意味着什么?
上面我已经给大家介绍了很多关于Shader 3.0新版本中的一些特色技术。那么心切的玩家一定已经按耐不住了,究竟Shader 3.0给我们在游戏中带来了哪些特色呢?在此之前很多游戏开发商都会吹嘘自己的游戏已经支持Shader 3.0技术。但以前我们并没有分辨出来Shdaer 2.0和3.0之间有多少差异。这原因有两个,第一虽然游戏开发人员在游戏中使用了Shader 3.0的部分函数,但这并不十分彻底。大步分的游戏源代码为了保持更好的向下兼容性,还是沿用古老的Shader 1.x函数库。其次,NVIDIA的GeForceFX系列的核心设计都是沿用了NV30的设计,ATI的Radeon系列也是大多使用R350的核心。虽然他们的Shader指令的处理能力达到了Shader 3.0的水平,但是芯片整体的架构设计却相差甚远。
但是现在随着NV40和R420的发布,我们终于有了可以完美运行Shdaer 3.0的硬件平台。并且最近我又发现了一款大量运用Shader 3.0函数库来构图的游戏——Far Cry。它已经运用了上述所有的Shader 3.0中的技术和特效。在使用GeForce 6800 Ultra运行该款游戏,并打开Pixel Shader 3.0选项的时候,我们可以明显的看到游戏运行速度大大提高。并且画面质量更加优秀,强面的凹凸感觉更加逼真。
(如图1使用Pixel Shader 2.0 ,如图2使用Pixel Shader 3.0)
使用Pixel Shader 2.0生成的佛像看上去就像一件未完成的草稿。而使用Pixel Shader 3.0之后,佛像面部表形细致入微,表面更显石头的质感,前身那些凹凸的雕琢也细致可见。
(如图3使用Pixel Shader 2.0 ,如图4使用Pixel Shader 3.0)
如此逼真的画面都要归功于Pixel Shader 3.0附加的一些视觉特效。游戏开发人员主要可以使用浮点材质数值过滤和架构缓冲混合。在这些独特的帧缓冲架构混合中游戏开发人员能够创造出逼真的运动模糊效果。这跟先前3DFx的T-Buffer的设计理念非常类似。浮点材质数据主要可以改善画面的质量,例如它可以改善高级动态范围数据的编译速度。这种高级的特效我们其实已经早在Half-Life 2的Pixel Shader 2.0中就感受过了,现在的浮点材质过滤又把这种特效提高到了一个新的层次。
总结
Shader 3.0相对于早期的3D加速硬件架构和游戏开发人员的思维模式来说都是一个不小的突破。同时它也提供了不少有趣的特效处理。对于所有的新技术来说,最大的困难还是投入成本和研发周期的问题。NVIDIA和ATI未来新一代显卡仅仅是Pixel Shader 3.0标准的试验品罢了。在Shader还有很多标准尚待完善,3.0版本也仅仅是下一代DircetX10的铺路石。针对新一代显卡作Shader 3.0优化的游戏也还需要很长的时间才能与我们见面。