实时渲染(第四版)_第3章|GPU并行架构及着色器(下)

这一篇文章主要接着上一篇,介绍各种着色器的特点以及作用:

顶点着色器

这是GPU流水管线的第一个阶段。是完全可编程的阶段。正如其名,他只处理传入的顶点数据,比如位置、颜色、法线、纹理坐标等。顶点着色器通常会将顶点从模型控件转换到齐次裁减空间,因此顶点着色器必须输出他的位置。

顶点着色器既不能创建和销毁顶点,也不能将一个顶点处理的结果传到另一个顶点。每个顶点都是被独立处理的。

顶点着色器适用于如下场景:
1、 通过一次性的创建网格并通过顶点着色器使其变形来创建物体
2、 通过使用皮肤和变形技术来使得角色身体和面部具有动画
3、 程序上的变形,比如旗帜、布料或水的移动
4、 通过发送退化网格到流水管线下端,并依据需要给定一定区域来生成粒子
5、 通过使用整个帧缓冲生成一个屏幕对齐的纹理去进行程序变形来制作:光学变形、热雾、水波、页面卷曲以及其他的效果
6、 通过顶点纹理获取应用到地形高度领域

部分效果如图(左侧是普通的茶壶,中间是被顶点着色器执行的简单裁剪操作,右侧噪声功能使模型扭曲):

vertex.png

曲面细分着色器

曲面细分着色器最主要的作用是将曲面转换成一组三角形。这是一个可选择的着色器。他具有如下的几个优点:
曲面细分比提供相应的三角形描述一个曲面会更加紧密;节省内存;在处理角色或物体动画上可以防止CPU到GPU之间运转的瓶颈;使用适当的三角形可以有效的呈现曲面。比如:一个球距离摄像机很远,那么只需要渲染几个三角形就可以了;如果距离很近,那么可能就要上千的三角形来渲染曲面。这种控制细节等级的能力也可以应用程序控制性能,比如在低性能GPU上使用低质量的网格来保持帧率。

曲面细分阶段包括了三个子阶段:在DX中称为外壳着色器、曲面细分和域着色器
他们之间的执行关系如图所示:

11.png

输入外壳着色器的是一个特殊的补丁图元:定义曲面的控制点,贝塞尔曲面补丁或者其他类型的曲面元素。外壳着色器有两个功能:它会告诉曲面细分阶段有多少个三角形需要生成,以及他们的结构;以及对每个控制点进行处理;可选择性的,外壳着色器可以更改传进来的补丁,也可以增加或者删除控制点。外壳着色器输出一系列的控制点,伴随着曲面细分阶段处理的数据,传到域着色器。

曲面细分阶段在流水管线中是固定执行阶段,只与曲面细分着色器一起使用。他的任务是通过外壳着色器传过来的有关曲面细分有关的信息:三角形、四边形或者等值线,以及曲面细分因子,来添加新的顶点,并计算每个顶点的相对位置。

域着色器类似顶点着色器。它主要是处理从外壳着色器以及曲面细分阶段传送过来的顶点,生成相应的输出顶点,沿着流水管现传送下去。
部分效果如图(左侧是大概6000三角形的模型,右侧是每个三角形使用PN三角形细分的效果):


12.png

几何着色器

几何着色器可以将一个图元转换成其他图元。它位于曲面细分着色器的后面,也是一个可选的着色器。

几何着色器输入的是单个模型以及其关联的顶点。对象通常是由三角形带、线或单个点。几何着色器也可以定义和处理拓展图元。几何着色器处理图元并输出0或者更多的顶点,这些顶点被视为点、折线或三角形带。注意,几何着色器可以没有任何输出。在这种方式下,网格可以通过编辑顶点有选择的修改、增加或移除图元。

几何着色器是为了更改输入的数据或者制作有限数量的副本而设计的。例如:生成6个转换后的副本去同时渲染立方体纹理的6面;高效创建阴影纹理去显示高质量阴影;从点数据创建可变粒子;皮毛渲染;为阴影算法寻找物体边缘等。

几何着色器需要确保输出图元的结果与输入时候的顺序一致,这会影响性能。因为如果一些着色器代码是并行运行的,结果必须被保存以及排序,这一点因素不利于几何着色器在一次调用中辅助或创建大量几何图元。

几何着色器的行为是最不可预测的,需要考虑资源和内存。实际上,几何着色器很少使用,因为他不能很好的映射出GPU的优势。
常见效果如图(左侧,金属球等值面曲面细分被GS动态执行。中间,使用GS进行线段不规则曲面细分以及流输出,广告牌被GS生成以显示闪电。右侧,通过使用顶点和几何着色器和流输出执行布料模拟):

geometry.png

流输出

通常GPU流水管线的标准使用是发送数据经过顶点着色器,然后光栅化三角形,在到像素着色器中处理。这些数据通过流水管线并且中间结果不能被访问。着色器模型4.0添加了流输出的概念。在顶点着色器处理过顶点之后,这些顶点数据可以输出到一个流中,即一个顺序数组,附加的传送到光栅化阶段。实际上,光栅化可以完全关闭,流水管线纯粹作为一个无图像流处理器。这种方式处理的数据可以通过流水管线返回,从而允许迭代处理。可以用在模拟水流或其他粒子效果。

流输出返回的数据都是浮点类型的数据,因此会有显著的内存消耗。另外流输出是在图元上工作的,而不是直直接在顶点上。如果网格被传到流水管线下端,每个三角形都会生成他自己的三个输出顶点集,原始网格上的任何共享顶点将丢失。由于这个原因,更典型的使用是仅仅将顶点作为顶点图元集通过流水管线传送。

像素着色器

在顶点、曲面细分和几何着色器执行之后,图元将被裁减以及光栅化处理。光栅化计算出三角形覆盖每个像素单元的面积,部分或者完全重叠像素的三角形这一部分称为片元。三角形顶点的值,包括深度缓冲区的Z值,将会通过三角形表面,为每个片元插值运算,片元以及插值数据一起传送到像素着色器。像素着色器实际上处理的是片元,而不是真正的像素。所有在OpenGL中,也称为片元着色器。

像素着色器主要是计算并输出片元的颜色,同样可以产生不透明值以及可选择性的更改他的Z深度值。像素着色器还具有特有的能力:丢弃一段片元,即,不输出此片元的数据。

最初,像素着色器仅仅只能输出到合并阶段。但是随着GPU的发展,像素着色器可执行的指令数量在增加。其中就有多重渲染目标的指令。不同于仅仅将像素着色器程序结果发到颜色和深度缓冲区,可以为每个片元生成多重设置数值并保存到不同的缓冲区,每个缓冲区成为渲染目标。多重渲染目标在高效执行渲染算法上是强有力的辅助工具。一个渲染通道用来生成颜色图像,另一个生成对象标识符,第三个生成世界空间距离等。比如延迟渲染:第一个通道存储关于每个像素的物体位置和材质数据,第二个通道进行光照计算和其他特效,其中可见性和着色是在单独的通道中完成的。

像素着色器还有一个限制是:他只能处理对应的片元,而不能从相邻的像素中读取结果。也就是当像素着色器程序执行时,他不能将输出结果发送给相邻像素,也不能访问其他像素数据。但是有例外,比如像素着色器在梯度或者导数计算时可以间接的访问相邻片元信息。但是梯度信息不能受动态流程控制影响的像素着色器访问,即if语句或可变数量的迭代循环,所有组内的片元必须使用同一设置的指令进行处理,即使是在离线渲染系统,这也是一个最基本的限制。

合并

合并阶段是处理单独的片元深度以及颜色值(像素着色器生成)并与帧缓冲区合并的地方。如果片元可见,那么他将和缓冲区的像素颜色进行混合。对于不透明的片元,那么片元只是简单的替换像素颜色,而对于透明的片元,才算的上是真正意义上的混合。

如果通过片元通过了像素着色器的计算到达了合并阶段,但是根据深度值发现,他是被其他像素覆盖着的,那么他在像素着色器中的计算将相当于是一次浪费。为了避免这种情况,有一些GPU采用early-z技术,即在像素着色器之前进行深度检测,见检测其可见性,如果不可见则不会传送到像素着色器进行计算。但是前面说到像素着色器具有改变z深度值或者完全剔除片元的能力,如果在像素着色器程序中有这两种任何一种操作,early-z通常不能使用,并且要关闭。合并阶段是高度可配置的,我们可以决定混合操作的模式等。

计算着色器

计算着色器并没有规定在图形管线的什么位置执行。他和其他着色器一样,有相同的数据输入集并且可以访问缓冲区(比如纹理)用来输入输出。计算着色器被线程组执行,每个线程组都有一段小内存在线程间共享。计算着色器最重要的优点在于他们可以访问GPU生成的数据。后处理是指渲染后的图形进一步进行处理,是计算着色器的常见用途。共享内存意味着从采样像素的结果可以与相邻线程共享。例如,使用计算着色器去确定一个图像的分布或平均亮度,其运行速度是像素着色器执行此操作的两倍。

计算着色器同样用于粒子系统,网格处理比如面部动画,裁剪,图像过滤,改善深度精度,阴影,区域深度,以及其他的任何一组GPU处理器可以处理的任务。
常见效果如图(左侧使用计算着色器进行模拟风吹头发的效果,头发本身是用曲面细分执行的;中间,计算着色器执行快速模糊操作,右侧,模拟波浪):


13.png

小结

主要是了解各个着色器的特点及其作用。至此,所有有关的介绍就结束了,从下一章开始就真正进入了图形学的重头戏。接下来的几篇将带领大家进入图形学最重要的基础:转换。
参考资料:Real-Time-Rendering-4th

你可能感兴趣的:(实时渲染(第四版)_第3章|GPU并行架构及着色器(下))