hlsl中文书

上传人:gu****n 文档编号:71515562 上传时间:2022-04-07 格式:DOC 页数:43 大小:1.90MB
收藏 版权申诉 举报 下载
hlsl中文书_第1页
第1页 / 共43页
hlsl中文书_第2页
第2页 / 共43页
hlsl中文书_第3页
第3页 / 共43页
资源描述:

《hlsl中文书》由会员分享,可在线阅读,更多相关《hlsl中文书(43页珍藏版)》请在装配图网上搜索。

1、谁应该阅读这本书? 这本书的主题是Shader开发和管理,是为所有需要在应用程序中使用shader的开发人员而准备。如果你对shader感兴趣,并希望把它高效集成到程序中,那么你该阅读本书。由于本书既可以作为学习指南,同时也是参考手册,因此无论对普通爱好者还是专业开发者,都会有所帮助。 此外,本书的组织方式同样适合于作为学校在计算机科学中开展实时图形渲染技术教学的教科书来使用。本书将讨论哪些内容? The Complete Effect and HLSL Guide的主题是shader开发和管理,这也是所有我们将要关注的内容。由于编写这本书的目的既是作为学习指南,同时也是参考手册,我将会覆盖H

2、LSL语言和effect framework的大部分内容,但不会讨论关于特定shader和渲染技术。以下是本书将要讨论的内容摘要:l 详细介绍DirectX SDK中的HLSL着色语言以及effect framework。l 深入讨论HLSL的语法和原理。l 覆盖了effect framework中所有主要的组件,以及如何运用和组织这些技术,来开发一个着色器管理框架。技术支持 http:/www.ParadoxalP包含了本书的所有技术支持。网站将会定期发布勘误和必要的更新。 如果你对本书由任何意见或问题,随时欢迎您联系我:Sebastien St-Laurent,sebastien.st.l

3、aurent第一部分 HLSL着色语言 欢迎阅读The Complete Effect and HLSL Guide。正如书名所示,贯穿本书的所有章节,我们将探索DirectX effect framework和HLSL(Hight-Level Shading language高级着色语言)的世界。你将学习如何高效的使用HLSL着色语言。此外,我还将教你如何使用effect framework。作为DirectX SDK的一部分,effect framework帮助你把shader集成到应用程序中。无论开发3D应用程序或视频游戏,为了适应shader日益增加的复杂度,同时保证向后兼容性,eff

4、ect framework无疑是集成和管理shader的首选。 编写这本书背后的目的有两个。首先,它作为一本学习指南,将带领你深入了解HLSL和effect framework。然而,更重要的是,本书还可以作为一本参考手册!它包含了所有没有包含在DirectX文档中,但对于编写shader来说必不可少的信息。哦,让我们不要浪费时间了,快速进入主题吧。 本书的第一部分将着重讲解HLSL着色语言,包括它的语法,以及用法。第二部分则聚焦于effect framework,展示使用effect framework管理应用程序中的shader是多么简单。好了,接下来我们就深入学习HLSL着色语言。第一章

5、 着色器和HLSL语言 过去几年来,shader技术取得了巨大飞跃。这一章,我将讲解HLSL着色语言的基本语法(syntax)和用法。为了让学习过程变得容易一些,我把对HLSL语法的描述分散到了多个章节中,每一章讲述着色语言的几个特定部分。本章将介绍基本语法,并且对基础知识进行一些概括。接下来的几章则着重讨论特定部分。 在开始介绍HLSL语法之前,先花一点时间来了解学习本书需要做的准备,以及一些关于HLSL着色语言和effect framework的历史。准备工作 虽然本书是关于HLSL和effect framework的,但并不会教你基本的DirectX和Direct3D知识。因此,最重要的

6、准备条件就是你必须对基本的DirectX API有一些了解,此外还需要具备一些3D渲染技术的基础知识。即使你对3D图形一窍不通,以上两点也很容易学习。 除了知识方面的要求,下面还列出了将会用到的软件和硬件:l DirectX 9.0 Summer 2004 Update SDK (包含在CD中)l Windows 2000(with service pack 2)或者Windows XP(家用或专业版)。l 奔腾3或更高的处理器l 最少256MB内存l 高端的3D图形卡。虽然任何图形卡都可以,但如果想尝试shader编程的所有方面,最好使用支持Shader Mode 2.0或3.0的图形卡。l

7、 最新的显卡驱动程序 准备工作做好之后,就可以开始学习和开发shader,利用effect framework了。现在你已经知道如何来使用本书。那么让我们了解一点关于shader和effect framework的历史。一点点历史. 从1995年,3Dfx发布第一块消费级的3D硬件加速图形卡开始,计算机图形技术和相关的硬件技术都取得了重大进展。虽然这类图形卡在渲染功能上有诸多限制,但为开发者打开了一片新的天地,终结了只能依靠软件解决方案进行渲染的时代。其结果是让实时3D图形和游戏都变得更加真实。 此后,接下来的几代硬件都在性能和功能方面有了重大突破。但是,由于受到硬件固定管线构架(fixed-

8、pipeline architecture)的限制,仍然有很多约束,开发者被强制只能通过使用和改变渲染状态来控制渲染过程,获得最终的输出图形。 固定管线构架功能上的局限性,限制了开发者创建所需效果的能力。总的来说,它所产生的图形都不够真实。另一方面,用于电影CG渲染的高端软件渲染构架则发明了一些让渲染更加逼真的方法。Pixar Animation Studios开发了一门称为RenderMan的着色语言。它的目的是让艺术家和开发者使用一门简单但强大的编程语言来完全控制渲染过程。RenderMan可以创建出高质量的图形,从照片级的真实效果,到卡通风格的非真实渲染效果都可以实现。被广泛用于当今的电

9、影中,包括著名的动画Toy Story和A Bugs Life。 随着处理器芯片制造技术的革新,和处理能力的增强,RenderMan的思想逐渐影响并延伸到了消费级图形硬件。DirectX 8的发布引入了顶点(vertex)和像素着色器(pixel shader)1.0 以及1.1版本。虽然这两个版本的着色模型灵活性不高,同时缺乏流程控制等一些功能。但是,这第一步,给予了艺术家和开发者长久以来所梦想的,创造夺目的、真实的图形的能力。消费级图形卡所生产的图形终于能和好莱坞电影工作室所渲染出的图形相比了。 接下来的几年间,图像硬件和3D API无论在功能和性能上都取得了巨大飞跃,甚至打破了摩尔定律中

10、的技术进步速率。随着DirectX 9.0 SDK以及最新的一代图形卡的发布,比如Nvidia的Geforce FX系列和ATI的Radeon 9800系列,顶点和像素着色器发展到了2.0和2.x版本。以及随后的3.x版本。 注意:摩尔定律是1965年,由戈登摩尔(Gordon Moore)intel的创建者之一,通过统计得出的结论:集成电路上可容纳的晶体管数目,约每隔一年便会增加一倍。他还预测在以后的几十年中仍然将是这样。至今为止,这条理论依然很正确。另外,由于晶体管数量与集成电路的性能有关,因此,摩尔定律也是硬件性能增长的预测的依据。 这些新的着色模型为实时图像程序开发者带来了前所未有的灵

11、活性。然而,大部分shader都通过一种低级的,类似于汇编的语言来编写的。这意味着作为一名开发人员,你必须像多年前使用汇编语言的时代那样,自己管理寄存器,分配变量以及优化。此外,shader model 2.0和3.0增加的复杂性让开发人员更加头疼,因为不同的图形卡寄存器数量不一样,甚至同样的指令执行结果也不一样。 为了简化shader开发,同时,给予硬件开发者更多的自由优化性能,微软在DirectX 9.0中引入了High-Level Shading Language(HLSL)。这门语言和其他高级语言,比如C或C+很类似,这样,开发者就能把注意力集中在shader所要实现的功能上,而不是把

12、精力放在如何使用寄存器,或对某种硬件如何组合指令才能最优化之类的琐碎问题上。 在讲解HLSL能做什么,以及如何来使用它之前,先来看看不同的shader版本可以提供哪些功能。需要说明的是,在编写shader之前,需要知道硬件都有哪些功能(capable)。使用HLSL并不能消除特定硬件平台上的限制,但却可以把这些限制隐藏起来。顶点和像素着色器管线以及Capabilities 与随DirectX 8.0发布的顶点和像素着色器1.0和1.1版本相比,shader model 2.0对语言进行了许多重要改进。由于最新的DirectX 9.0所使用的顶点和像素着色器版本为2.0,同时,已经有大量支持ve

13、rtex和pixel 2.0的显卡,所以本书主要讨论基于这一技术的shader。 注意:虽然在编写本书时,支持shader model 3.0的图形卡已经开始上市,但尚未普及。我们会讨论一些shader model 3.0的特性,但大部分例子都是基于2.0或更低版本的shader技术。 假设你已经有一定的3D和shader基础知识,我们来看看第二代着色语言和上一代技术相比有哪些比较重要的改变。 顶点着色器2.0和2.x相对于1.x的版本有如下改进:l 支持整数和布尔数据类型,并分别有相应的设置指令。l 增加了临时和常量寄存器的数量。l 对程序所能包含的最大指令数进行了增加,给开发者以更多灵活性

14、(标准所要求的最小指令数从128增加到了256,某些硬件还能支持更多指令)。l 添加了许多支持复杂运算的宏指令,比如 sine/cosine,absolute,以及power等。l 支持流程控制语句,比如循环和条件测试。 下面列出的则是像素着色器 2.0和2.x相对于1.x版本的改进:l 支持扩展32-bit精度的浮点运算。l 支持对寄存器元素的任意重组(swizzling)和遮罩(masking)。l 增加了常量和临时寄存器的可用数量。l 标准所允许的最小指令卡有明显增加。算术指令从8条增加到64条,同时还允许使用32条纹理指令。像素着色器 2.x默认情况下甚至支持更多指令,允许硬件支持比标

15、准最小要求多的指令数。l 支持整数和布尔常量,循环计数器以及断言寄存器(predicate register)。l 支持动态流程控制,包括循环和分支。l Gradient instrctions allowing a shader to discover the dervate of any input register 通过这一系列强大的改进,如今,开发者可以自由发挥想象力,创造出令人吃惊的效果。到这里,我们应该学习一下两种着色器的构架,以便更好的了解数据是怎样在图形硬件上流动。 当渲染3D图形时,几何体信息通过Direct3D之类的渲染API传递给图形硬件。硬件一旦接收到这些信息,就为me

16、sh中的每一个顶点调用顶点程序。图1.1描绘了顶点和像素着色器2.0标准实现的原理图。 从图1.1中可以看到,开发者通过3D渲染API,以数据流的形式,为顶点着色器提供顶点数据。数据流中包含了正确渲染几何体所需的所有信息,包括顶点位置,颜色和纹理坐标等等。当这些信息传递进来时,将分别放到合适的输入寄存器v0到v15中,以便顶点着色程序使用。顶点程序还需要访问许多其他的寄存器,才能完成自己的工作。常量寄存器都是只读的,通常用来为shader储存静态数据,因此,必须预先设置好它们的值。顶点着色器2.0标准下,常量寄存器储存的都是矢量,可以保存浮点数,整数,以及布尔类型的值。需要注意,顶点着色器中所

17、有的寄存器都把数据储存为包含4个分量的矢量,可以并行访问所有分量,也可以使用重组或遮罩分别访问某个分量。 在图1.1的右边部分,是临时寄存器,用来储存顶点着色器计算出的中间结果。显然,由于它们是临时性的,因此,可以对这些寄存器进行写入和读取操作。注意名称为a0到aL的寄存器,它们是循环时用来索引地址和追踪循环所用的计数寄存器(counter register)。记住,由于HLSL是一门高级的着色语言,你不需要关心寄存器是如何分配的。对开发者来说这个过程应该是透明的,并且只有在shader被最终编译为机器代码时才发生。 在访问了输入寄存器,临时寄存器和常量寄存器之后,顶点着色器程序才开始以开发者

18、所希望的方式来处理和控制输入的顶点。处理过程结束之后,结果立即被输送到最终的输出寄存器中。其中关键字 定义true 这个关键字表示布尔类型中的true常量。详见第二章中关于数据类型的部分。typedef 这个关键字用来定义一个新的数据类型。详见第二章中关于数据类型的部分。uniform 这个变量用来把变量定义为uniform的,这表示在所有着色器运行时,这个变量的初始值都不会改变。详见第二章中关于数据类型的部分。vector 这个关键字用来表示一个矢量类型的数据。详见第二章中关于数据类型的部分。vertexfragment 这个关键字用来定义一个顶点片断(或着色器)。void 这个关键字表示一

19、个void(或empty)数据类型。详见第二章中关于数据类型的部分。volatile 这个关键字用来提示编译器一个变量将会频繁改变。详见第二章中关于数据类型的部分。while 这个关键字用来定义条件do-while循环 上面这个表可能看起来太枯燥了,特别是对于HLSL的初学者,甚至会感到有些迷惑。不要担心。这本书既是学习指南也是参考书。表1-1中的信息主要作为参考信息来使用。当我们学习HLSL语法和示例程序时,你就知道如何来使用它了。这一章里,我将会指出HLSL中所有主要的语法和文法(grammar)元素。在以后章节中再逐渐深入。 除了表1-1中的关键字外,还有一系列HLSL目前没有使用的保留

20、关键字。这些关键字是为今后语言扩充所预留的,表1-2列出了这些保留关键字:表 1-2HLSL保留关键字auto break case catchdefaultdelete dynamic_caseenumexplicitend goto longmutable namespacenew operatorprivateprotected publicreinterpret_caseshortsigned sizeofstatic_castswitchtemplate this throwtry typename unionunsignedusingvirtual词汇约定 虽然语法定义了如何把所有

21、语言元素组合到一起,比如,如何定义函数和代码片段,但它只定义了如何把表达式和操作符以及标识符一起使用。这意味着语言的语法并没有定义文法(例如: 什么是标识符)。接下来的几段详细解释了HLSL编译器中的词汇约定。空白字符HLSL语言中,下面这些字符都被认为是空白字符:l 空格l Tab字符l 换行符l C风格的注解(/* */)。l C+风格的注解( / )。l asm代码块中,汇编风格的注解(;)。数字 HLSL中的数字可以为浮点类型,也可以为整型。浮点数通常有以下呈现形式:Float: ( fractional-constant exponent-part float-suffix )| (

22、digit-sequence exponent-part float-suffix )Fractnal-const: ( digit sequence . digit sequence ) | (digit squence . )Sign: + | -Dight sequence: digit | (digit sequence digit )floating suffix: h | H | f | F整型的语法与此类似:Integer: integer constant interger suffix Integer constant: digit sequence | ( 0 digit

23、sequence ) | ( 0 digit sequence )Digit sequence: digit | ( digit sequence digit )Integer suffix: u | U | l | L字符 HLSL允许定义字符和字符串。字符串都是由字符组成。下面是字符的定义:l c (字符)l t , n ,.( 转义字符 )l # (八进制换码顺序 )l x# (十六进制换码顺序) 注意预处理指令中不能包含转义字符。 字符串包含在一对引号中,可以包含前面所述的任意有效字符组合。标识符 标识符用来表示函数名或变量名之类的语言元素。除了前面所列的关键字以外,标识符可以是字母和

24、数字的任意组合,但必须保证第一个字符为字母。操作符 HLSL定义了一组操作符,以便在表达式中使用。表1-5 列出了所有标准操作符,以及他们的含义。如果你熟悉C或C+,那么这些操作符对你来说应该是一目了然的。表 1-5 HLSL 操作符操作符 描述+ 一元加法。- 一元减法。& 逻辑与。| 逻辑或。= 等号。: 成员标识符(用于结构和类)。 二进制左移。= 自赋值(self assigning)二进制左移,a= b等于a = a 二进制右移。= 自赋值二进制右移,a=b等于a = ab。 省略符(用于可变参数函数)。= 大于等于。!= 不等于。*= 自赋值乘法, a *= b 等于 a = a

25、* b。/= 自赋值除法, a /= b 等于 a = a / b。+= 自赋值加法, a += b 等于 a = a + b。-= 自赋值减法, a -= b 等于 a = a b。%= 自赋值求余, a %= b 等于 a = a % b。&= 自赋值逻辑与, a &= b 等于a = a & b。|= 自赋值逻辑或, a |= b 等于 a = a | b。= 自赋值求幂, a = b 等于 a = a b。- 重定向操作符,用来访问结构成员。语言语法 HLSL语言的语法相当简单。初看可能有些复杂,但只要使用它写几个程序,你马上就能掌握要领。目前为止,你不应该对语法太过担心,后面的章节我

26、们将逐步了解语言的每个部分。由于实际的语法表相当长,我决定单独把他放到附录D中。另外你也可以参考DirectX SDK获取更多信息。 (译注:请参考DirectX SDK中DirectX Graphics-Reference-HLSL Shader Reference-Appendix中的Language Syntax部分) 观察表的第一行,可以看到HLSL程序被定义为一个program。每个program要么为空,要么包含一系列decl(声明)。最初的两行表示每个decls可以由多条其它decl组成。你可能已经注意到,声明可以用来定义空白语句,类型声明,变量声明,结构声明,函数声明或tech

27、nique声明。语义定义了不同声明类型等等。小结以及接下来的内容 在这一章里,我们简要概括了DirectX和shader技术在过去几年间的发展和历史。随着shader model 2.0和3.0复杂度的增加,开发者不但需要利用语言的所有新能力,同时,还需要高效的完成任务。由于新着色管道的指令和通用处理器上的指令越来越类似,因此,开发一门高级语言,让开发者把注意力集中在shader所要实现的功能上,而不是把精力放在如何使用寄存器,或对某种硬件如何组合指令才能最优化之类的琐碎问题上是很有意义的。 在需求的驱动下,微软开发并通过DirectX SDK发布了HLSL着色语言,帮助开发者使用最新的图形技

28、术,创建更加真实的图形。本章,我们学习了很多语法背后的基础知识。虽然这章看起来有些枯燥,不要担心,随后的几个章节我们就会讨论一些比较有趣的内容。第二章 HLSL着色语言 这一章我们将学习HLSL的大部分基本内容,包括丰富的变量类型,如何定义变量,和如何编写shader代码。你可能还想知道如何在shader中使用函数。虽然它们是使用HLSL编写shader的必须元素,但我还是决定把所有关于函数的内容作为单独一章来讲解。在第三章中,我们将详细讲解如何定义函数,以及HLSL为开发者所编写的内置函数。 在继续学习之前,需要进行一点点说明,读者在前一章学习HLSL语法时可能注意到了诸如technique

29、s,渲染状态,pass之类的概念。虽然它们也是HLSL语言的一部分,但事实上它们只在effect文件中使用,而effect 文件则是HLSL的一个超集。 好了,闲谈到此为止,让我们直接进入本章主题,讨论在任何语言中都是最重要的元素,数据类型。数据类型 数据类型是任何一门编程语言的核心。没有它们你将无法定义变量或者在函数之间传递数据。如果连呈现数据的方法都没有,又怎么能储存数据呢?和其他高级语言一样,HLSL有一系列内置定义类型,可以把它们分为以下几类:l 标量类型l 矢量类型l 矩阵类型l 对象类型 除了上面的内置类型外,HLSL同样允许自定义的复合类型,比如数组和结构。在介绍HLSL特定数据

30、类型前,先来仔细看看大部分3D硬件上呈现数据的方式。当处理数据时,基本的选项是浮点值,根据硬件构架的不同,这些值可能为16或32位。记住,虽然可以让硬件同一时间只处理一个值,但这并不是最高效的方法。相反,如果硬件每次处理一个包含四个分量值的单元(或矢量),那么则可以同时对四个分量进行处理。当然,这就需要考虑硬件如何来保存非矢量的值。我稍后会讲解这一点。 除了浮点值以外,较新的硬件也内置支持整型和布尔值,但它们主要用于分支,循环,和条件测试语句。接下来的几页中,我将浏览每一种数据类型,并解释如何来使用它们。标量类型 标量类型是由HLSL标准定义的,他们是最基本的类型。所有复杂类型,比如矢量,矩阵

31、,和结构都由标量组成。表2-1列出了所有可用的标量类型以及它们所表示的值。表 2 -1 HLSL标量类型标量类型 值bool true或falseint 32位有符号的整型half 16位浮点数float 32位浮点数double 64位浮点数 需要注意并不是所有shader目标都天生支持整型,half和double值。如果要将shader编译为不支持指定类型数据的目标,那么将模拟处理float值的方式来处理它们。与使用原生(native)类型相比,结果可能不正确。在确定目标平台支持某个特定类型之前,为了保证一致性和可移植性,最好坚持使用标准浮点数。注意我们在上一章已经简要讨论过profile

32、,它用来告诉HLSL编译器为哪种构架的shader产生代码。通常Profile的值直接对应于可用的顶点和像素着色器版本,但对于指令集没有改变的情况可能会有例外。矢量和矩阵类型 矢量和矩阵是把标量组织为1维或2为数组的标准方式。它们通常用来表示3D数据,比如法线和变换矩阵。 矢量是HLSL标准所定义的,由特定标量类型组成的一维数组。默认情况下,一个矢量由4个浮点值组成。如表2-2所示,可以手动定义任何类型的矢量。表 2 -2 HLSL矢量类型矢量类型 值vector 一个包含四个浮点分量的矢量vector 包含size个type类型的矢量 另外,为了简便,HLSL语言预定义了一组标准矢量类型,方

33、便开发者使用。下面就是这些预定义的矢量类型typedef vector VECTOR;typedef vector bool# ;typedef vector int# ;typedef vector half# ;typedef vector float# ;typedef vector double# ;(译注:“#”表示分量个数。) 你可能还记得我之前提到过图形硬件是基于矢量的。你看,这里所定义的矢量数据类型恰好与硬件相对应,编译器将把这些数据直接映射为矢量。当你使用少于四个分量的矢量时,编译器将在空闲分量中添加其他变量,以便压缩数据。 简要讨论了矢量之后,你可能想知道如何才能单独访问矢

34、量中的某个分量。有许多方式允许我们单独访问矢量中的分量。下面列出了访问数组分量的几种不同方式。注意对多于四个分量的数组来说,额外的分量只能通过索引访问。l 使用分量符访问:vector.x , vector.y , vector.z , vector.wl 使用颜色符访问:vector.r , vector.g , vector.b , vector.al 使用索引访问:vector0, vector1, vector2, vector3 接下来看看矩阵类型。矩阵是HLSL标准所定义的,由特定标量类型组成的二维数组。默认情况下分量访问和重组 如前所述,可以像访问结构成员一样来访问矢量和矩阵中的

35、单个分量。这里对矢量和矩阵的访问方式做个小结。 _11, x, r _12, y, g _13, z, b _14, w, a _21 _22 _23 _24 _31 _32 _33 _34 _41 _42 _43 _44 此外,通过把二到四个分量名串连到一起作为下标来使用,还可以让矢量只包含某几个指定分量,HLSL把这门技术称为重组。这里就是一些有效的重组实例: bgr, yyzw, _12_22_32_42 对矩阵来说也是如此。 tempMatrix._m00_11 = worldMatrix._m00_m11; tempmatrix._11_22_33 = worldMatrix._24

36、_23_22; temp = fMatrix._m00_m11; temp = fMatrix._11_22; 注意,所有下标都必须来自于同一下标集,(比如xyzw,rgba,或者_11到_44),不同下标集之间的元素不能进行混合,比如不能出现xyrg这样的组合。同一个分量可以出现多次。但对赋值目标来说,则不允许分量重复出现。注意并不是所有硬件都支持所有类型的重组操作。对像素着色器1.x的某些版本来说,部分重组操作是不允许的。编译器可以通过模拟来补偿这些限制,但将带来一定性能损失。对象类型 HLSL还定义了一系列范围广泛的对象数据类型。这些类型通常用来呈现非数字数据与复合类型的句柄,典型的例子

37、就是纹理和结构体。以下是HLSL中所定义的对象类型:l 采样器l 纹理l 结构体l 顶点和像素着色器l 字符串 结构的内容将在下一节关于自定义类型的部分详细讨论。 字符串指使用ASCII码定义的字符串,它们除了用作注解以外,用处不是太多,这里也不对它进行详细讨论。采样器,着色器和纹理才是我们所关心的重点部分。采样器和纹理 HLSL定义了两种数据类型用于在shader中获取纹理信息。纹理本质上就是一个指向硬盘上一系列物理像素信息的句柄。采样器则是一组纹理采样参数的组合,比如warp mode或者mipmap属性等。顶点和像素着色器 HLSL定义了两种数据类型用来保存顶点和像素着色器,它们分别是v

38、ertexshader和pixelshader。如果使用asm关键字以汇编方式来编写着色程序,则可以把这些程序直接分配给着色器:vertexshader vs = vs_2_0 decl_position v0 mov oPos, v0; 如果使用HLSL,那么则必须通过函数来定义着色器。下面就是使用高级指令定义像素着色器的例子: pixelshader ps = compile ps_2_0 psmain();结构及自定义类型 除了前面看到的大量预定义数据类型以外,HLSL也允许开发者创建新类型。自定义类型通常都是结构,它们是由一组其他(内置或自定义)数据类型,或基于现有类型声明的新类型,组

39、成的对象。 使用关键字struct来定义结构。结构是复合类型,用来把多个数据组合为一个整体。用下面的语法来定义结构: struct ID members 这里是创建结构的一个例子:struct Circle float4 Position; float Radius; 另外,HLSL还允许使用typedef关键字,为现有类型声明一个新名称。它的语法如下: typedef const type id array_suffix , id; 数组后缀可以跟随在ID之后,允许把数组作为新类型。当声明了一个类型之后,就可以通过ID来对它进行引用。注意array_suffix由一个或多个literal_i

40、nteger_expression组成,用来表示数组维度。类型转换 在程序设计中,术语类型转换表示把一种数据转变为另一种数据的能力。HLSL支持多种内置类型间的转换。表2-4总结了内置数据间可能的转换。表 2 -4 HLSL中的类型转换转换类型 描述标量标量 这类转换总是有效的。当把布尔值转换为整型或浮点类型时,false值表示0,true表示1。同样,当把整型或浮点类型转换为布尔值时,0表示false。当把浮点类型转换为整型时,将四舍五入为最接近的整数。标量矢量 这类转换总是有效的。转换将把标量复制并填充到矢量中。标量矩阵 这类转换总是有效的。转换将把标量复制并填充到矩阵中。标量对象 这类转

41、换是是无效的。标量结构 这类转换仅当结构中的成员都为数字时才是有效的。转换将把标量复制并填充到结构中。矢量标量 这类转换总是有效的。转换将复制矢量中的第一个分量,并填充到标量中。矢量矢量 目标矢量容量不大于源矢量时才是有效的。转换只保留最左边(left-most)的分量,截去剩下的分量。矢量矩阵 只有当矢量和矩阵一样大时,转换才是有效的。矢量对象 这类转换总是无效的。矢量结构 这类转换只有当结构容量不大于矢量,且所有成员都为数字时才是有效的。矩阵标量 这类转换总是有效的。转换将把矩阵左上角的值填充到标量中。矩阵矢量 只有当矢量和矩阵一样大时转换才是有效的。矩阵矩阵 只有当目标矩阵维度不大于源矩

42、阵时,转换才是有效的。转换将把源矩阵填充到目标矩阵的左上部分,并且丢弃余下数据。矩阵对象 这类转换总是无效的。矩阵结构 只有当结构容量和矩阵一样大,且所有成员都为数字时,转换才是有效的。对象标量 这类转换总是无效的。对象矢量 这类转换总是无效的。对象矩阵 这类转换总是无效的。对象对象 只有当两个对象都是同一类型时,转换才是有效的。对象结构 只有当结构包含一个以上的成员时,转换才是有效的。结构中成员的类型必须和对象的类型一样。结构标量 只有当结构包含一个以上的成员时,转换才是有效的。这个成员必须为数字。结构矢量 只有当结构容量不小于矢量时,转换才是有效的。它的第一个成员必须为数字,并且等于矢量的

43、大小。结构矩阵 只有当结构容量不小于矩阵时,转换才是有效的。它的第一个成员必须是数字,并且等于矩阵大小。结构结构 只有当目标结构容量不大于源结构容量时,转换才是有效的。目标结构和源结构间各自成员的转换也必须是有效的。定义变量 HLSL允许把变量定义为常量,输入,输出和临时变量。变量的标准定义语法如下: static uniform vloatile extern shared const type id array_suffix :semantics = initializers annotations , id ; 从语法定义规范可以看出,对变量可以使用多个变量关键字前缀,来告诉编译器如何对

44、待变量。表2-5列出了不同前缀所表示的含义。表 2 5 变量前缀前缀 描述static static用于全局变量,表示值为一个内部变量,仅能被当前shader中的代码访问。用于局部变量则表示这个值将在多次调用间驻留。静态变量只能进行一次初始化操作,如果没有使用特定值进行初始化,则默认为0。uniform 使用uniform声明的全局变量表示对整个shader来说,它是一个统一的输入值,即不能在shader运行期间改变。所有非静态全局变量都被认为是统一的。extern 使用extern声明的全局变量表示对shader来说,它是一个外部输入的值。所有非静态全局变量都被认为是外部的。volatile

45、 这个关键字提示编译器变量将频繁改变。shared 这个关键字用来修饰非全局变量,告诉编译器这个值将被多个effect共享。const 声明为const的变量表示在初始化之后,就不能改变它的值。 声明变量的语法中,需要注意的是semantics部分。语义(semantixs)对HLSL语言来说并没有什么特别含义,它是用来定义如何把shader中的变量及变量的含义映射到effect framewrok中的。 语义通常用于顶点和像素程序的输入和输出变量,把他们映射为特定含义,比如顶点位置或纹理坐标。举例来说,COLOR0语义用来告诉编译器,指定变量表示第一种漫反射颜色,并且在大多数shader版本

46、中,将把它放到d0寄存器中。 如语法定义规范所示,允许全局变量包含一个注解(annotation)。注解以 member_list 的形式出现。Member_list是一个程序声明的集合,其中每个成员都被初始化为指定字面值。注解只能用来为effect传递元数据,不能在程序中对它进行引用。 我们将在第六章详细讨论语义和注解。语句和表达式 与其它高级语言一样,HLSL也包含语句和表达式。虽然这些元素通常作为函数的一部分来使用,而我们要在下一章才讲解函数。但由于他们是构建shader的主要元素,因此,现在就来看看这些元素。语句 语句用来控制程序流的执行顺序。HLSL定义了多种类型的语句供开发者使用。

47、下面按功能的不同,对这些语句分为了四类:l 表达式l 语句块l 返回语句l 流程控制语句 接下来将详细讨论上面的每种元素,第一项是表达式,但我想把它们放到这节的后面一点,先来看看第二项,语句块。 简单来说,语句块就是包含在一对大括号中的语句集合。它把语句组织为一个群组,同时定义了一个子范围,块中所定义的变量只存在于当前语句块范围中。 statements 接下来看返回语句。返回语句用于把函数执行的结果返回给调用者。它的语法如下: return expresstion ; 上面可以看出,使用return关键字和一个紧随的表达式来定义返回语句。记住,为了让程序通过编译,表达式类型必须和函数所定义的

48、返回值类型相匹配。 最后一项流程控制语句,它们用来控制程序的执行顺序:if ( expression ) statement else statement do statement while ( expression )while (expression) do statementfor ( expression | variable_decleration ; expression ; exxpression )statement 可以看到,HLSL中的流程控制语句与C或C+中的基本相同。但与C或C+不同的是,在shader中使用流程控制语句,必须进行一些性能上的考虑。流程控制性能考虑 目

49、前,大多数顶点和像素着色器硬件都以线性方式执行shader,每条指令执行一次。HLSL支持的流程控制形式包括静态分支,断言指令,静态循环,动态分支和动态循环。由于某些着色器实现的限制,部分流程控制指令可能会带来重大的性能损失。 举例来说,顶点着色器1.1版的构架并不支持动态分支,因此使用if语句,产生的汇编代码将同时实现if语句中所有代码。Shader将顺序执行完这些代码,但只使用if语句中某一块代码的输出作为结果。这里是一段将使用vs_1_1编译的程序:if ( Value 0 ) Position = Value1;else Position = Value2; 下面是编译之后的汇编代码:/ 在r0.w中计算线性插值量mov r1.w, c2.xslt r0.w, c3.x, r1.w/根据比较结果对Value1和Value2进行插值move r7, -c1add r2, r7, c0mad oPas, r0.w, r2, c1 从上面的代码可以看到,在顶点着色器模型1.1中使用if语句,将导致if语句中的所有表达式都被执行,之后通过插值来计算最终输出。在真正支持动态分支的情况下,这个语句

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!