|
图形渲染流水线,也简称为“流水线”流 水线的主要功能是生成或渲染给定虚拟相机、三维物体、光源等的二维图像。 因此,渲染管道是实时渲染的基础工具。
1、Architecture
实时渲染流水线分4个主要阶段,应用、几何处理、光栅化、逐片元处理
顾名思义,应用程序阶段由应用程序驱动,因此通常在运行于通用 cpu 上 的软件中实现。这些 cpu 通常包括能够并行处理多个执行线程的多个核心。 这使 cpu 能够有效地运行应用程序阶段所负责的各种各样的任务。传统上在 CPU 上执行的一些任务包括碰撞侦测、全局加速算法、动画、物理模拟等等, 这取决于应用程序的类型。下一个主要阶段是几何处理,处理变换、投影和 所有其他类型的几何处理。这个阶段计算要绘制什么,应该如何绘制,以及 应该在哪里绘制。几何级通常在一个包含许多可编程内核和固定操作硬件的 图形处理器处理器(GPU)上执行。光栅化阶段通常将三个顶点作为输入,形成 一个三角形,并找到三角形内的所有像素,然后将这些像素转发到下一个阶 段。最后,像素处理阶段按每个像素执行程序以确定其颜色,并可执行深度 测试以查看其是否可见。它还可以执行逐像素操作,例如将新计算的颜色与 以前的颜色混合。光栅化和像素处理阶段也完全在 GPU 上处理。所有这些阶 段及其内部管道将在接下来的四个部分中讨论。图形处理器如何处理这些阶段的更多细节在。
2、The Application Stage
开发人员可以完全控制在应用程序阶段发生的事情,因为它通常在 CPU 上执 行。因此,开发人员可以完全确定实现,并在以后修改它以提高性能。这里 的更改也会影响后续阶段的性能。
例如,一个应用程序阶段算法或设置可以减少绘制的三角形数量。所有这些都表明,一些应用程序的工作可以通过 GPU 来完成,使用一个单独的compute shader。这种模式将 GPU 视为高度并行的通用处理器,而忽略了其 专门用于渲染图形的特殊功能。
在应用阶段结束时,将渲染的几何图形提供给几何处理阶段。这些是渲染原始数据(rendering primitives),例如,点、线和三角形,它们最终可能出现在屏幕上(或者使用任何输 出设备)。这是应用阶段最重要的任务。
然而,为了提高性能,这个阶段经常在几个处理器核心上并行执行。在 CPU 设计中,这被称为超标量结构,因为它能够在同一阶段同时执行多个进程。(第 18.5 节介绍了使用多个处理器核心的各种方法)
在这个阶段通常实现的一个过程是碰撞侦测。在检测到两个物体之间的碰 撞之后,可以生成响应并发送回碰撞物体以及力反馈装置。应用阶段也是处 理来自其他来源的输入的地方,比如键盘、鼠标或者头戴式显示器。根据这 个输入,可以采取几种不同的操作。加速算法,例如特定的剔除算法(第 19 章),也在这里实现,以及其他管道无法处理的算法。
3、Geometry Processing
图形处理器上的几何处理阶段负责大部分的每三角形和每顶点操作。这个阶段进一步划分为以下几个功能阶段:顶点着色、MVP变换、裁剪和屏幕映射。
1.Vertex Shading
随着现代 GPU 的出现,伴随着每像素发生的部分或全部阴影,这个顶点阶段更加普遍,根据程序员的意图可能根 本不计算任何阴影方程。顶点着色器现在是一个更一般的单位,用于设置与 每个顶点相关的数据。例如,顶点着色程序可以使用和中的方法使一个对象 产生动画效果。
在模型到达屏幕的过程中,模型被转换成几个不同的空间或坐标系。最初,模型驻留在它自己的模型空间中,这仅仅意味着它根本没有被转换。每个模型都可以与一个model transform相关联,这样它就可以被定位和定向。可以将多个模型转换 与单个模型关联起来。这允许同一模型的多个副本(称为实例)在同一场景中具有不同的位置、方向和大小,而不需要复制基本的几何图形。
通过模型变换转换的是模型的顶点和法线。一个物体的坐标称为模型坐标, 在将模型变换应用于这些坐标之后,模型被称为位于世界坐标或世界空间中。 世界空间是独一无二的,在模型经过各自的模型变换后,所有的模型都存在于同一空间中。
只呈现相机(或观察者)看到的模型。相机在世界空间中有一个位置和一个方向,用来定位和瞄准相机。为了方便投影和裁剪,相机和所有的模型的转换是视图变换。视图变换的目的是将摄像机放置在原点并瞄准它, 使它看起来在负 z 轴的方向上,y 轴向上,x 轴向右。我们使用-z 轴约定;有些 文本倾向于使用+z 轴。两者之间的差别主要是语义上的,因为这两者之间 转换很简单。应用视图转换后的实际位置和方向取决于底层应用程序编程接口(API)。这样勾勒出的空间称为摄像机空间
2.Optional Vertex Processing
每个管道都有刚才描述的顶点处理。一旦这个处理完成,有一些可选的阶段, 可以发生在 GPU 上,按照这样的顺序:曲面细分,几何shader,和stream output。
1.Tessellation Shader
第一个任选阶段是曲面细分。想象你有一个球对象。如果您使用一组三 角形来表示它,则可能会遇到质量或性能方面的问题。你的球在 5 米远的地方看起来可能很好看,但是靠近一些单独的三角形,特是沿着轮廓,就可 以看到了。如果你使用更多的三角形来提高画面质量,你可能会浪费大量的处理时间和内存,因为球离得很远,而且只覆盖了屏幕上的几个像素。通过曲面细分,一个曲面可以生成适当数量的三角形。
这样的曲面可以通过一组patches来指定,每个patches由一组顶点组成。曲面细分阶段由一系列阶段组成,包括hull shader、tessellator和domain shader,这些阶段通常会将这些顶点集转换成更大的顶点集,然后用这些顶点集生成新的三角形集。场景的摄像头可以用来确定生成了多少个三角形:patch关闭时生成了很多个三角形(不理解),远离时生成了很少的三角形。
2.Geometry Shader
下一个可选阶段是几何着色器。这个着色器早于 tessella-tion 着色器,所以 在 gpu 上更常见。它像tessella着色器,它采用各种各样的原语,可以产生新的 顶点。这是一个非常简单的阶段,因为这个创建的范围是有限的,输出primitives的类型也是非常有限的。几何着色器有多种用途,其中最受欢迎的是粒子产生。想象一下模拟烟花爆炸。每个火球都可以用一个点,一个顶点来表示。几何着色器可以把每个点变成 一个正方形(由两个三角形组成),面向观察者并覆盖几个像素.
3.Stream Output
最后一个可选的阶段称为流输出。这个阶段让我们使用 GPU 作为一个几 何引擎。与将处理过的顶点沿管道的其余部分发送到屏幕上相反,此时我们 可以选择将这些顶点输出到一个数组中进行进一步处理。这些数据可以由 CPU 使用,或者 GPU 本身在以后的传递中使用。这个阶段通常用于粒子模拟,例如我们的焰火例子。
这三个阶段是按照这个顺序进行的ーー—tessellation, geometry shading, and stream outputーー每个 阶段都是可选的。无论使用哪个选项(如果有的话),如果我们继续沿着管道向下,我们有一组带有齐次坐标的顶点,将检查相机是否查看它们。
3.Clipping
只有全部或部分在视图体积内的primitives需要传递到光栅化阶段(以及后续的像素 处理阶段),然后在屏幕上绘制它们。完全位于视图卷中的primitives将按原样传递到下一个阶段。完全在视图卷之外的primitives不会进一步传递,因为它们不会呈现。需要裁剪的是部分位于视图体内的primitives。例如,有一个顶点在外面,一 个在视图体积内的直线应该根据视图体积来裁剪,这样外面的顶点就会被位 于直线和视图体积之间的交点上的新顶点所替换。使用投影矩阵意味着将变 换后的primitives裁剪到单位立方体上。在裁剪之前执行视图转换和投影的优点是 它使裁剪问题保持一致;总是将primitives裁剪到单位立方体上。
剪裁过程除了视图体积的六个剪切平面之外,用户还可以定义 额外的剪切平面来明显地切割对象。
剪裁步骤使用由程序产生的 4 值齐次坐标来执行剪裁。值通常不会在透视 空间中跨三角形线性插值。需要使用第四个坐标,以便在使用透视投影时对 数据进行适当的跨极化(inter-polated)和裁剪。最后,进行透视分割,将生成的三角形的位置置于三维NDC(normalized device coordinates)中。如前所述,这个view volume的范围从(-1,-1,-1)到 (1,1,1)。几何阶段的最后一步是从这个空间转换到屏幕坐标。
4.Screen Mapping
只有视图体积中的(clipped)primitives被传递到屏幕地图平移阶段,进入这个阶段时 坐标仍然是三维的。每个基元的 x 坐标和 y 坐标被转换为屏幕坐标。屏幕坐 标和 z 坐标也称为窗口坐标。假设场景应该呈现在一个窗口中,最小角位于 (x1,y1),最大角位于(x2,y2),其中 x1x2 和 y1y2。然后,屏幕映射是一个平移,接着是一个缩放操作。新的 x 坐标和 y 坐标称为屏幕坐标。Z-coordinate([-1,+1]forOpenGLand [0,1]forDirectX)也映射到[z1,z2]。这步构造的坐标也就是NDC,这些都可以通过 API 进行修改。窗口坐标和重新绘制 的 z 值一起传递到光栅化阶段。屏幕映射过程见。
我们将描述整数和浮点值与像素(和纹理坐标)之间的关系。给定 一个像素水平排列并使用笛卡尔坐标,最左边缘的像素在浮点坐标中为 0.0。 Opengl 一直使用这种方案,而 directx10 及其后继者使用它。这个像素的中心 位于 0.5。因此,一个像素范围[0,9]覆盖了从[0.0,10.0]的范围。这个转换过程 很简单
其中 d 是像素的离散(整数)索引,c 是像素内的连续(浮点)值。
虽然所有 api 都有从左向右增加的像素位置值,但是在某些情况下, OpenGL 和 DirectX 之间的顶部和底部边缘的零位置是不一致的。2OpenGL 支 持笛卡尔系统,将左下角视为最低值元素,而 DirectX 有时根据上下文将左上 角定义为这个元素。每个问题都有其逻辑性,不同的问题没有正确的答案。 例如,(0,0)在 OpenGL 中位于图像的左下角,而在 DirectX 中位于左上角。在 从一个 API 转移到另一个 API 时,必须考虑到这种差异。
“Direct3D”是 DirectX 的三维图形 API 组件。Directx 包括其他 API 元素,比 如输入和音频控件。在讨论这个特定 API 时,我们没有区分在指定特定发行 版时编写“DirectX”和在讨论这个特定 API 时编写“Direct3D”,而是遵循通常的用法,自始至终编写“DirectX”。
4、Rasterization
左图:栅格化分为两个功能阶段,称为三角形设置和三角形遍历。右 图:像素处理分为两个功能阶段,即像素处理和合并。
是否认为三角形重叠的像素取决于你如何设置 GPU 的管道。例如,您可 以使用点采样来确定“insideness”最简单的情况是在每个像素的中心使用一个点样本,因此如果中 心点在三角形内部,那么相应的像素也在三角形内部。您还可以使用超采样 或多采样反走样技术()对每个像素使用多个采样。还有一种方法是使用保守的 光栅化,其定义是,如果像素至少有一部分与三角形重叠,那么像素就在三 角形的“内部”(第 23.1.2 节)。
1.Triangle Setup
在这一阶段,微分,边缘方程和其他数据的三角形计算。这些数据可用于三 角形遍历(),以及插值由几何阶段产生的各种shading数据。此任务使用固定功能硬件。
2.Triangle Traversal
将检查三角形覆盖其中心(或样本)的每个像素,并为重叠于三角形的 像素部分生成片段。更详细的抽样方法可以在(5.4节)。找到三角形内部的样本或像 素通常被称为三角形遍历。每个三角形片段的属性是使用插值在三个三角形 顶点(Cahpter 5)中的数据生成的。这些属性包括碎片的深度,以及来自几何阶段的任何shading数据。McCormack等人[1162]提供了更多关于三角形穿越的信息。在三角形上执行透视校正插值[694](第 23.1.1 节)。然后将primitives中的所有像素 或样本发送到下一步描述的像素处理阶段。
5、Pixel Processing
此时,作为前面所有阶段组合的结果,已经找到了在三角形或其他primitives中考 虑的所有像素。这个像素处理阶段分为像素着色和合并,如右图所示。像素处理是对primitives中的像素或样本进行每像素或每样本(片元)计算和操作的阶段。
1.Pixel Shading
这里将使用插值后的 shad-ing 数据作为输入,执行每个像素的阴影计算。最 终的结果是一个或多个颜色被传递到下一个阶段。不像三角形设置和遍历阶段,通常是执行专用的硬件特性(不可编程),像素着色阶段是执行可编程的 GPU 核心。 为此,程序员为像素着色器(在 OpenGL 中称为fragment shader)提供一个程序,它 可以包含任何想要的计算。这里可以采用各种各样的技术,其中最重要的是纹理技术。纹理是在更详细的处理在Chapter 6。 图像可以是一维、二维或三维的,最常见的是二维图像。最简单地说,最终product是每个片段的颜色值,这些颜色值被传递到下一个子阶段。
2.Merging
每个像素的信息存储在颜色缓冲区中,该缓冲区是一个颜色矩形阵列(对于每 种颜色,一个红色、一个绿色和一个蓝色组件)。合并阶段的职责是将由像素 着色阶段产生的片段颜色与当前存储在缓冲区中的颜色结合起来。这个阶段 也称为 ROP,代表“光栅操作(管道)”或“渲染输出单元”,这取决于您询问的对 象。与shading阶段不同,执行这一阶段的 GPU 子单元通常不是完全可编程的。 但是,它是高度可配置的,能够实现各种效果。
Z 缓冲区的 大小和形状与颜色缓冲区相同,对于每个像素,它将 z 值存储到当前最接近 的基元。这意味着,当一个基元被渲染到某个像素时,将计算该像素上该基元上的 z 值,并将其与同一像素上的 z 缓冲区内容进行比较。如果新的 z 值小 于 z 缓冲区中的 z 值,那么正在渲染的原语比以前在该像素处最接近摄像机 的原语更接近摄像机。因此,该像素的 z 值和颜色将使用正在绘制的原语中 的 z 值和颜色进行更新。如果计算出的 z 值大于 z 缓冲区中的 z 值,那么颜色 缓冲区和 z 缓冲区将保持不变。Z-buffer 算法非常简单,具有 o(n)收敛性(其 中 n 是要渲染的原语数量),并且适用于任何可以为每个(相关)像素计算 z 值 的绘图原语。还要注意,这个算法允许大多数原语以任何顺序呈现,这是它 受欢迎的另一个原因。但是,z 缓冲区在屏幕上的每个点只存储一个深度,因 此不能用于部分透明原语。这些图形必须在所有不透明原语之后呈现,并且 以后到前的顺序,或者使用单独的与顺序无关的算法()。透明性是基本 z 缓冲 区的主要弱点之一。
我们已经提到过,颜色缓冲区用于存储颜色,而 z 缓冲区存储每个像素的 z 值。但是,还可以使用其他通道和缓冲区来过滤和捕获片段信息。Alpha 通 道与颜色缓冲区相关联,并为每个像素()存储相关的不透明度值。在旧的 api 中,alpha 通道也被用来通过 alpha 测试特性有选择地丢弃像素。现在,丢弃 操作可以插入到像素着色程序中,任何类型的计算都可以用来触发丢弃。这 种类型的测试可以用来确保完全透明的片段不会影响 z 缓冲区()。
模板缓冲区是一个离屏缓冲区,用于记录呈现primitives的位置。它通常每像素 包含 8 位。可以使用各种函数将primitives呈现到模板缓冲区中,然后可以使用缓冲区的内容控制渲染到颜色缓冲区和 z 缓冲区。例如,假设一个已填充的圆已经被绘制 到模具缓冲区中。这可以与一个操作符相结合,该操作符只允许将后续的primitives呈现到存在圆的颜色缓冲区中。模具缓冲区可以是一个强大的工具,生成 一些特殊的效果。管道末端的所有这些功能称为光栅操作(ROP)或混合操作。 可以将当前在颜色缓冲区中的颜色与正在三角形中处理的像素的颜色混合。 这可以使效果,如透明度或积累的颜色样本。如前所述,混合通常可以使用 API 进行配置,但不能完全编程。然而,有些 api 支持光栅顺序视图,也称为像素着色器顺序,它支持可编程混合功能
framebuffer通常由系统上的所有缓冲区组成。
当primitives已经达到并通过光栅化阶段,那些是可见的从相机的角度来看,显 示在屏幕上。屏幕显示颜色缓冲区的内容。为了避免让人类查看primitives,因为它们被光栅化并发送到屏幕上,使用了双缓冲。这意味着场景的渲染是在屏幕之外的后台缓冲区中进行的。一旦场景在后台缓冲区中呈现,后台缓冲区 的内容就会与之前显示在屏幕上的前台缓冲区的内容进行交换。交换通常发 生在vertical retrace期间,这个时间段是安全的。
6、Conclusion
需要注意的是,这并不是唯一可能的渲染管道;离线渲染管道经历了不同的演 化路径。电影制作中的渲染通常是用微多边形管道[289,1734]来完成的,但是 光线追踪和路径追踪是最近才出现的。这些第 11.2.2 节所述的技术,也可用于建筑和设计的预视化。
下一章:Cahpter3 The Graphics processing Unit: |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|