图形渲染管线
引言
本博客介绍了实时图形学中的核心组件,它被称为“图形渲染管线(graphics rendering pipeline)”,也被简称为“管线”。
渲染管线的核心功能就是利用给定的虚拟相机、三维物体、光源等信息,来生成或者渲染(render)一张二维图像。因此, 渲染管线是实时渲染中的底层工具
渲染管线的架构
一种粗略的划分方法是将渲染管线分为四个阶段——应用阶段(application)、几何处理阶段(geometry processing)、光栅化阶段(rasterization)和像素处理阶段(pixel processing)

渲染速度可以用每秒帧数(FPS)来进行表示,即每秒显示的帧数;也可以用赫兹 (Hz)来进行表示,这个单位代表了 ,即更新的频率。
- 应用阶段(application)是由应用程序进行驱动的,它在软件中进行实现,运行在通用 CPU 上。这些 CPU 一般都具有多个核心,可以并行处理多个线程 (thread)的任务,这使得 CPU 可以高效执行由应用阶段所负责的各种任务,一般 CPU 会负责碰撞检测,全局加速算法,动画,物理模拟等任务,具体会执行哪些任 务取决于应用程序的类型。
- 下一个主要阶段是几何处理阶段(geometry processing),它负责处理变换(transform),投影(projection)以及其他所有和 几何处理相关的任务。这个阶段需要计算哪些物体会被绘制,应该如何进行绘制,以 及应当在哪里绘制等问题。几何阶段通常运行在硬件处理单元(GPU)上,它包含一 系列的可编程单元和固定操作硬件。
- 光栅化阶段(rasterization)通常会将构成一个 三角形的三个顶点作为输入,找到所有位于三角形内部的像素,并将其转发到下一个 阶段中。
- 最后一个阶段是像素处理阶段(pixel processing),对于每个像素而言, 都会执行一个程序来决定它的颜色;并执行深度测试,来判断这个像素是否可见;这 里还可以执行一些逐像素的操作,例如将新计算的颜色和之前的颜色进行混合。
光栅化阶段和像素处理阶段同样完全运行在 GPU 上
应用阶段
由于应用阶段通常都运行在 CPU 上, 因此开发者可以完全控制在应用阶段发生的事情
有一些应用阶段中的任务也可以让 GPU 来进行执行,即通过使用一个叫做计算着色器(compute shader)的独立模式,该模式会将 GPU 视为一个高度并行 的通用处理器,而忽略其专门用于图形渲染的特殊功能
在应用阶段的最后,需要进行渲染的几何物体会被输入到几何处理阶段中,这些几何物体被称作为渲染图元(rendering primitive),即点、线和三角形。
碰撞检测(collision detection)通常会在这个阶段中实现。当检测到两个物体之间的碰撞之后,会产生相应的响应,并返回给碰撞物体,同时也返回给力反馈设备(如果有的话)。
应用阶段同样也是处理其他来源输入的地方,例如键盘、鼠标或者头戴式显示器等,会根据不同的输入,从而采取不同的操作。此外,一些加速算法例如特殊的剔除算法等,以及渲染管线剩余部分无法处理的一切问题,都会在应用阶段中完成。
几何处理阶段
运行在 GPU 上的几何处理阶段会负责大部分的逐三角形(per-triangle)和逐顶点 (per-vertex)操作。将几何处理阶段再细分下去,可以划分为以下几个功能性阶段:顶点着色(vertex shading)、投影(projection)、裁剪(clipping)和屏幕映射(screen mapping),如图 2.3 所示.

顶点着色
顶点着色(vertex shading)的任务主要有两个
- 一个是计算顶点的位置
- 另一个是计算那些开发人员想要作为顶点数据进行输出的任何参数,例如法线(normal)和纹理坐标(texture coordinate)等
顶点着色器如今是一个更加通用的单元,它负责计算并设置与每个顶点都相关的数据。例如顶点着色器可以用来计算物体的动画。
首先我们描述一下顶点位置是如何被计算出来的,它需要一组顶点坐标来作为输入。 在物体最终进入屏幕的过程中,它需要在不同的空间(space)或者坐标系 (coordinate system)下,进行若干次变换
接下来,我们将描述顶点着色的第二类输出。为了创建一个真实的场景,仅仅是渲染物体的位置和形状是不够的,我们还需要对物体的外观信息进行建模,包括物体的材质(material)信息以及光源照射在物体表面上的效果。从最简单的颜色描述到基于物理的详细描述,材质和光源可以通过很多方式进行建模。
确定光照作用于材质上所产生的效果,这个操作被称为着色
顶点着色的结果(可能是颜色、向量、纹理坐标或者其他类型的着色数据)会被发送到光栅化阶段中进行插值,并在像素处理阶段中用于计算表面的着色。
作为顶点着色的一部分,渲染系统还会进行投影操作和裁剪操作,这两个操作会将整个可视空间变换为一个标准立方体,这个标准立方体被称为规范可视空间(canonical view volume)
首先会进行投影操作,这是在 GPU 上的顶点着色器中完成;
有两种常见的投影方法, 一种是正交投影(orthographic),也可以叫做平行投影(parallel);另一种是透视投影(perspective)
可选的顶点管理
每个渲染管线中,都会有刚才所描述的顶点处理阶段,当完成顶点处理之后,还有几个可以在 GPU 上执行的可选操作,它们的执行顺序如下:曲面细分 (tessellation)、几何着色(geometry shading)和流式输出(stream out)。
曲面细分
想象有一个用三角形表示的曲面小球,我们从远看看的就是一个小球,但是离近看就会发现三角形,所以曲面细分就可以帮我们为一个曲面生成数量合适的三角形,这样就可以做到性能与质量兼顾
曲面细分阶段本身也包含了一系列子阶段——壳着色器 (hull shader)、曲面细分器(tessellator)和域着色器(domain shader),它们可以将当前的顶点集合(通常)转换为更大的顶点集合,从而创建出更多的三角形。
几何着色器
这个着色器出现的比曲面细分着色器更早,因此在 GPU 上也更加常见。它和曲面细分着色器的相似点在于,它也将各种类型的图元作为输入,然后生成新的顶点。
这是一个较为简单的阶段,因为它能够创建的范围是有限的,能够输出的图元则更加有限
几何着色器有好几种用途, 其中最流行的一种就是用来生成粒子。想象我们正在模拟一个烟花爆炸的过程,每颗火花都可以表示为一个点,即一个简单的顶点。
流式输出
这阶段我们可以把GPU作为一个几何引擎
说人话就是把数据放在缓冲区,而不是直接输入到渲染管线后面流程并且直接输出到屏幕
这个阶段通常会用于粒子模拟,例如我们刚才所举的烟花案例
裁剪
我们只需要可视空间里面的图元,如果在可视空间外,则可以不用显示,如果一个三角形有一部分在可视空间外,就会直接裁剪,抛弃可视空间外的顶点,生成新的顶点
我们使用投影矩阵来将可视空间变成一个立方体,这意味着所有的图元都需要被这个标准立方体所裁剪。使用观察变换和投影变换可以保证裁剪的一致性
这里我们会采用投影变换的四维齐次坐标去完成这个剪切操作
屏幕映射
只有位于可视空间的图元我们才会传递到屏幕映射阶段。当这些图元进入到这个阶段的时候,坐标还是三维的,所以需要映射到屏幕的二维坐标
光栅化阶段
所有在前一阶段中被保留下来的图元,在这个阶段中都会进行光栅化,即找到所有位于图元内部的像素,然后将其发送管线的像素处理阶段
像素处理阶段
这一步的目标是计算出每个可见图元所覆盖像素的颜色值
总结
本章节介绍的就是面向实时渲染程序的API以及图形硬件发展而来的结果。
离线渲染中也有一套渲染管线,但是经历了与实时渲染完全不同的有演化路径