利器HLSL起步教程完整篇.docx
- 文档编号:12923364
- 上传时间:2023-06-09
- 格式:DOCX
- 页数:54
- 大小:1.13MB
利器HLSL起步教程完整篇.docx
《利器HLSL起步教程完整篇.docx》由会员分享,可在线阅读,更多相关《利器HLSL起步教程完整篇.docx(54页珍藏版)》请在冰点文库上搜索。
利器HLSL起步教程完整篇
HLSL起步
作者:
XX
前言
本教程针对HLSL(HighLevelShadingLanguage)初学者,从应用的角度对HLSL、顶点着色器、像素着色器和Effect效果框架进行了介绍,教程中去掉了对HLSL语法等一些细节内容的讨论,力求帮助读者尽可能快地理解HLSL编程的概念,掌握HLSL编程的方法。
教程中部分阐述直接引用了其他文档,这是因为这些文档表述之精要,已经达到了不能更改的地步,这里表示感谢。
本文档版权为作者所有,非商业用途可免费使用,转载请注明出处。
一点点历史….
从1995年,3Dfx发布第一块消费级的3D硬件加速图形卡开始,计算机图形技术和相关的硬件技术都取得了重大进展。
虽然这类图形卡在渲染功能上有诸多限制,但为开发者打开了一片新的天地,终结了只能依靠软件解决方案进行渲染的时代。
其结果是让实时3D图形和游戏都变得更加真实。
此后,接下来的几代硬件都在性能和功能方面有了重大突破。
但是,由于受到硬件固定管线构架(fixed-pipelinearchitecture)的限制,仍然有很多约束,开发者被强制只能通过使用和改变渲染状态来控制渲染过程,获得最终的输出图形。
固定管线构架功能上的局限性,限制了开发者创建所需效果的能力。
总的来说,它所产生的图形都不够真实。
另一方面,用于电影CG渲染的高端软件渲染构架则发明了一些让渲染更加逼真的方法。
PixarAnimationStudios开发了一门称为RenderMan的着色语言。
它的目的是让艺术家和开发者使用一门简单但强大的编程语言来完全控制渲染过程。
RenderMan可以创建出高质量的图形,从照片级的真实效果,到卡通风格的非真实渲染效果都可以实现。
被广泛用于当今的电影中,包括著名的动画ToyStory和ABug’sLife。
随着处理器芯片制造技术的革新,和处理能力的增强,RenderMan的思想逐渐影响并延伸到了消费级图形硬件。
DirectX8的发布引入了顶点(vertex)和像素着色器(pixelshader)以及版本。
虽然这两个版本的着色模型灵活性不高,同时缺乏流程控制等一些功能。
但是,这第一步,给予了艺术家和开发者长久以来所梦想的,创造夺目的、真实的图形的能力。
消费级图形卡所生产的图形终于能和好莱坞电影工作室所渲染出的图形相比了。
接下来的几年间,图像硬件和3DAPI无论在功能和性能上都取得了巨大飞跃,甚至打破了摩尔定律中的技术进步速率。
随着DirectXSDK以及最新的一代图形卡的发布,比如Nvidia的GeforceFX系列和ATI的Radeon9800系列,顶点和像素着色器发展到了和版本。
以及随后的版本。
注意:
摩尔定律是1965年,由戈登摩尔(GordonMoore)——intel的创建者之一,通过统计得出的结论:
集成电路上可容纳的晶体管数目,约每隔一年便会增加一倍。
他还预测在以后的几十年中仍然将是这样。
至今为止,这条理论依然很正确。
另外,由于晶体管数量与集成电路的性能有关,因此,摩尔定律也是硬件性能增长的预测的依据。
这些新的着色模型为实时图像程序开发者带来了前所未有的灵活性。
然而,大部分shader都通过一种低级的,类似于汇编的语言来编写的。
这意味着作为一名开发人员,你必须像多年前使用汇编语言的时代那样,自己管理寄存器,分配变量以及优化。
此外,shadermodel和增加的复杂性让开发人员更加头疼,因为不同的图形卡寄存器数量不一样,甚至同样的指令执行结果也不一样。
为了简化shader开发,同时,给予硬件开发者更多的自由优化性能,微软在DirectX中引入了High-LevelShadingLanguage(HLSL)。
这门语言和其他高级语言,比如C或C++很类似,这样,开发者就能把注意力集中在shader所要实现的功能上,而不是把精力放在如何使用寄存器,或对某种硬件如何组合指令才能最优化之类的琐碎问题上。
在讲解HLSL能做什么,以及如何来使用它之前,先来看看不同的shader版本可以提供哪些功能。
需要说明的是,在编写shader之前,需要知道硬件都有哪些功能(capable)。
使用HLSL并不能消除特定硬件平台上的限制,但却可以把这些限制隐藏起来。
顶点和像素着色器管线以及Capabilities
与随DirectX发布的顶点和像素着色器和版本相比,shadermodel对语言进行了许多重要改进。
由于最新的DirectX所使用的顶点和像素着色器版本为,同时,已经有大量支持vertex和pixel的显卡,所以本书主要讨论基于这一技术的shader。
注意:
虽然在编写本书时,支持shadermodel的图形卡已经开始上市,但尚未普及。
我们会讨论一些shadermodel的特性,但大部分例子都是基于或更低版本的shader技术。
假设你已经有一定的3D和shader基础知识,我们来看看第二代着色语言和上一代技术相比有哪些比较重要的改变。
顶点着色器和相对于的版本有如下改进:
支持整数和布尔数据类型,并分别有相应的设置指令。
增加了临时和常量寄存器的数量。
对程序所能包含的最大指令数进行了增加,给开发者以更多灵活性(标准所要求的最小指令数从128增加到了256,某些硬件还能支持更多指令)。
添加了许多支持复杂运算的宏指令,比如sine/cosine,absolute,以及power等。
支持流程控制语句,比如循环和条件测试。
下面列出的则是像素着色器和相对于版本的改进:
支持扩展32-bit精度的浮点运算。
支持对寄存器元素的任意重组(swizzling)和遮罩(masking)。
增加了常量和临时寄存器的可用数量。
标准所允许的最小指令卡有明显增加。
算术指令从8条增加到64条,同时还允许使用32条纹理指令。
像素着色器默认情况下甚至支持更多指令,允许硬件支持比标准最小要求多的指令数。
支持整数和布尔常量,循环计数器以及断言寄存器(predicateregister)。
支持动态流程控制,包括循环和分支。
Gradientinstrctionsallowingashadertodiscoverthedervateofanyinputregister
通过这一系列强大的改进,如今,开发者可以自由发挥想象力,创造出令人吃惊的效果。
到这里,我们应该学习一下两种着色器的构架,以便更好的了解数据是怎样在图形硬件上流动。
当渲染3D图形时,几何体信息通过Direct3D之类的渲染API传递给图形硬件。
硬件一旦接收到这些信息,就为mesh中的每一个顶点调用顶点程序。
图描绘了顶点和像素着色器标准实现的原理图。
从图中可以看到,开发者通过3D渲染API,以数据流的形式,为顶点着色器提供顶点数据。
数据流中包含了正确渲染几何体所需的所有信息,包括顶点位置,颜色和纹理坐标等等。
当这些信息传递进来时,将分别放到合适的输入寄存器v0到v15中,以便顶点着色程序使用。
顶点程序还需要访问许多其他的寄存器,才能完成自己的工作。
常量寄存器都是只读的,通常用来为shader储存静态数据,因此,必须预先设置好它们的值。
顶点着色器标准下,常量寄存器储存的都是矢量,可以保存浮点数,整数,以及布尔类型的值。
需要注意,顶点着色器中所有的寄存器都把数据储存为包含4个分量的矢量,可以并行访问所有分量,也可以使用重组或遮罩分别访问某个分量。
在图的右边部分,是临时寄存器,用来储存顶点着色器计算出的中间结果。
显然,由于它们是临时性的,因此,可以对这些寄存器进行写入和读取操作。
注意名称为a0到aL的寄存器,它们是循环时用来索引地址和追踪循环所用的计数寄存器(counterregister)。
记住,由于HLSL是一门高级的着色语言,你不需要关心寄存器是如何分配的。
对开发者来说这个过程应该是透明的,并且只有在shader被最终编译为机器代码时才发生。
在访问了输入寄存器,临时寄存器和常量寄存器之后,顶点着色器程序才开始以开发者所希望的方式来处理和控制输入的顶点。
处理过程结束之后,结果立即被输送到最终的输出寄存器中。
其中
关键字 定义
true 这个关键字表示布尔类型中的true常量。
详见第二章中关于数据类型的部分。
typedef 这个关键字用来定义一个新的数据类型。
详见第二章中关于数据类型的部分。
uniform 这个变量用来把变量定义为uniform的,这表示在所有着色器运行时,这个变量的初始值都不会改变。
详见第二章中关于数据类型的部分。
vector 这个关键字用来表示一个矢量类型的数据。
详见第二章中关于数据类型的部分。
vertexfragment 这个关键字用来定义一个顶点片断(或着色器)。
void 这个关键字表示一个void(或empty)数据类型。
详见第二章中关于数据类型的部分。
volatile 这个关键字用来提示编译器一个变量将会频繁改变。
详见第二章中关于数据类型的部分。
while 这个关键字用来定义条件do-while循环
上面这个表可能看起来太枯燥了,特别是对于HLSL的初学者,甚至会感到有些迷惑。
不要担心。
这本书既是学习指南也是参考书。
表1-1中的信息主要作为参考信息来使用。
当我们学习HLSL语法和示例程序时,你就知道如何来使用它了。
这一章里,我将会指出HLSL中所有主要的语法和文法(grammar)元素。
在以后章节中再逐渐深入。
除了表1-1中的关键字外,还有一系列HLSL目前没有使用的保留关键字。
这些关键字是为今后语言扩充所预留的,表1-2列出了这些保留关键字:
表1-2 HLSL保留关键字
auto break case catch
default delete dynamic_case enum
explicit end goto long
mutable namespace new operator
private protected public reinterpret_case
short signed sizeof static_cast
switch template this throw
try typename union unsigned
using virtual
词汇约定
虽然语法定义了如何把所有语言元素组合到一起,比如,如何定义函数和代码片段,但它只定义了如何把表达式和操作符以及标识符一起使用。
这意味着语言的语法并没有定义文法(例如:
什么是标识符)。
接下来的几段详细解释了HLSL编译器中的词汇约定。
空白字符
HLSL语言中,下面这些字符都被认为是空白字符:
空格
Tab字符
换行符
C风格的注解(/**/)。
C++风格的注解(digit–sequence)|(digit–squence.)
Sign:
+|-
Dight–sequence:
digit|(digit–sequencedigit)
floating–suffix:
h|H|f|F
整型的语法与此类似:
Integer:
integer–constant[interger–suffix]
Integer–constant:
digit–sequence|(0digit–sequence)|(0×digit–sequence)
Digit–sequence:
digit|(digit–sequencedigit)
Integer–suffix:
u|U|l|L
字符
HLSL允许定义字符和字符串。
字符串都是由字符组成。
下面是字符的定义:
‘c‘(字符)
‘\t‘,‘\n‘,…..(转义字符)
‘\###‘(八进制换码顺序)
‘\x##‘(十六进制换码顺序)
注意
预处理指令中不能包含转义字符。
字符串包含在一对引号中,可以包含前面所述的任意有效字符组合。
标识符
标识符用来表示函数名或变量名之类的语言元素。
除了前面所列的关键字以外,标识符可以是字母和数字的任意组合,但必须保证第一个字符为字母。
操作符
HLSL定义了一组操作符,以便在表达式中使用。
表1-5列出了所有标准操作符,以及他们的含义。
如果你熟悉C或C++,那么这些操作符对你来说应该是一目了然的。
表1-5HLSL操作符
操作符描述
++一元加法。
--一元减法。
&&逻辑与。
||逻辑或。
==等号。
:
:
成员标识符(用于结构和类)。
<<二进制左移。
<<=自赋值(selfassigning)二进制左移,a<<=b等于a=a<
>>二进制右移。
>>=自赋值二进制右移,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。
|=自赋值逻辑或,a|=b等于a=a|b。
^=自赋值求幂,a^=b等于a=a^b。
->重定向操作符,用来访问结构成员。
语言语法
HLSL语言的语法相当简单。
初看可能有些复杂,但只要使用它写几个程序,你马上就能掌握要领。
目前为止,你不应该对语法太过担心,后面的章节我们将逐步了解语言的每个部分。
由于实际的语法表相当长,我决定单独把他放到附录D中。
另外你也可以参考DirectXSDK获取更多信息。
(译注:
请参考DirectXSDK中DirectXGraphics--Reference--HLSLShaderReference--Appendix中的LanguageSyntax部分)
观察表的第一行,可以看到HLSL程序被定义为一个program。
每个program要么为空,要么包含一系列decl(声明)。
最初的两行表示每个decls可以由多条其它decl组成。
你可能已经注意到,声明可以用来定义空白语句,类型声明,变量声明,结构声明,函数声明或technique声明。
语义定义了不同声明类型等等。
小结以及接下来的内容
在这一章里,我们简要概括了DirectX和shader技术在过去几年间的发展和历史。
随着shadermodel和复杂度的增加,开发者不但需要利用语言的所有新能力,同时,还需要高效的完成任务。
由于新着色管道的指令和通用处理器上的指令越来越类似,因此,开发一门高级语言,让开发者把注意力集中在shader所要实现的功能上,而不是把精力放在如何使用寄存器,或对某种硬件如何组合指令才能最优化之类的琐碎问题上是很有意义的。
在需求的驱动下,微软开发并通过DirectXSDK发布了HLSL着色语言,帮助开发者使用最新的图形技术,创建更加真实的图形。
本章,我们学习了很多语法背后的基础知识。
虽然这章看起来有些枯燥,不要担心,随后的几个章节我们就会讨论一些比较有趣的内容。
入门
什么是着色器
DirectX使用管道技术(pipeline)进行图形渲染,其构架如下:
图Direct3DGraphicsPipeline
之前我们使用管道的步骤如下:
1. 设定顶点、图元、纹理等数据信息;
2. 设定管道状态信息;
渲染状态
通过SetRenderState方法设定渲染状态;
另外,使用以下方法设置变换、材质和光照:
SetTransform
SetMaterial
SetLight
LightEnable
取样器状态
通过SetSamplerState方法设定取样器状态;
纹理层状态
通过SetTextureStageState设定纹理层状态;
3. 渲染;
这部分交由D3D管道按照之前的设定自行完成,这部分操作是D3D预先固定的,所以这种管道技术被称为固定功能管道(fixedfunctionpipeline);
固定功能管道给我们编程提供了一定的灵活性,但是仍有很多效果难以通过这种方式实现,比如:
1. 在渲染过程中,我们要求y坐标值大于10的顶点要被绘制到坐标值(0,0,0)的地方,在之前的固定功能管道中,顶点被绘制的位置是在第1步即被设定好的,不可能在渲染过程中进行改变,所以是不可行的;
2. 某顶点在纹理贴图1上映射为点A,在纹理贴图2上映射为点B,我们要求该顶点颜色由A、B共同决定,即:
定点颜色=A点色彩值*+B点色彩值*
这在固定管道编程中也是不可行的。
以上两个问题都可以由可编程管道(pragrammablepipeline)来解决。
可编程管线允许用户自定义一段可以在GPU上执行的程序,代替固定管道技术中的VertexProcessing和PixelProcessing阶段(参照图),从而在使我们在编程中达到更大的灵活性。
其中替换VertexProcessing的部分叫做VertexShader(顶点着色器),替换PixelProccessing的部分叫做PixelShader(像素着色器),这就是我们所说的着色器Shader。
什么是HLSL
中,着色器是通过低级着色汇编语言来编写的,这样的程序更像是汇编式的指令集合,由于其效率低、可读性差、版本限制等缺点,迫切要求出现一门更高级的着色语言。
到了Direct3D9,HLSL(HighLevelShadingLanguage,高级渲染语言)应运而生了。
HLSL的语法非常类似于C和C++,学习起来是很方便的。
怎么写HLSL着色器
我们可以直接把HLSL着色器代码作为一长串字符串编写进我们的应用程序源文件中,但是,更加方便和模块化的方法是把着色器的代码从应用程序代码中分离出来。
因此,我们将着色器代码单独保存为文本格式,然后在应用程序中使用特定函数将其加载进来。
下面是一个完整的HLSL着色器程序代码,我们把它保存在中。
该着色器完成顶点的世界变换、观察变换和投影变幻,并将顶点颜色设定为指定的颜色。
1.3.11.3.21.3.3 该函数以input和output类型作为输入输出;
2. 使全局变量WVPMatrix和相乘,以完成顶点的世界、观察、投影变换,并把结果赋值到;
=mul,WVPMatrix);
3. 将全局变量color的值赋给;
=color;
4. 在同一个着色器代码文件中,可以有多个用户自定义函数,因此在应用程序中需要指定一个入口函数,相当于windows程序的WinMain函数,本程序只包含SetColor一个函数而且它将被做为入口函数使用。
1.3.4总结
至此,一个HLSL着色器编写完毕,渲染过程中,当一个顶点被送到着色器时:
1. 全局变量WVPMatrix、color将在应用程序中被赋值;
2. 入口函数SetColor被调用编译器根据标志符将顶点信息填充到VS_INPUT中的各个字段;
3. SetColor函数中,首先定义一个VS_OUTPUT信息,之后根据WVPMatrix和color变量完成顶点的坐标变换和颜色设定操作,最后函数返回VS_OUTPUT结构;
4. 编译器将会再次根据标志符把返回的VS_OUTPUT结构中的各字段映射为顶点相应的信息。
5. 顶点被送往下一个流程接受进一步处理。
上述过程中,全局变量在应用程序中赋值而在着色器程序中使用,这是应用程序和着色器通信的关键所在;标志符告诉编译器各个输入输出变量的用途(顶点位置、法线、颜色等),这是着色器代码和编译器、GPU之间通信的关键。
个人认为这是着色器中最为精义的地方:
)
怎么用HLSL着色器
应用程序中对HLSL着色器的使用分为以下步骤:
1. 加载(称为编译更为妥当)着色器代码;
2. 创建(顶点/像素)着色器;
3. 对着色器中的变量进行赋值,完成应用程序和着色器之间的通信。
4.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 利器 HLSL 起步 教程 完整