本文将介绍渲染流水线

渲染流水线简介

渲染流水线字面意思就是渲染的流水线,它将渲染的流程分成一个个工序,每个工序会不间断地对没有完成该工序的对象进行处理,这样所有对象都会并行地进行渲染流程,提高了单位时间内的生产量,而性能的瓶颈也将由耗时最长的工序决定。
渲染管线最终的目的就是为了将场景中的3D元素转换为屏幕上的2D图像,输出到用户的屏幕上

下图是在《【技术美术百人计划】图形 1.1 渲染流水线》讲解的PPT里面截的图片,相较于《Shader入门精要》更为详细:

第一张截图为简单版:

渲染流水线图例.png

第二张截图为详细版:

渲染流水线详细图例.png

接下来详细介绍每个阶段的具体操作。

各阶段详细介绍

CPU阶段

应用阶段

应用阶段是所有阶段中唯一在CPU中执行的,它会将渲染所需要的数据从硬盘加载到内存中,再调用Draw Call命令将网格和纹理等数据转换成渲染图元,并加载到显存中,因为显卡访问显存得更快,而且大部分显卡对于内存没有直接的访问权限。

Draw Call实际上就是一个命令,CPU发起,GPU接收,命令指向一个图元列表,GPU根据渲染状态和所有输入的顶点数据进行计算,最终输出到屏幕。

加载到显存后且CPU不会再访问的数据(例如有时可能需要使用网格计算碰撞则需要CPU访问网格数据)会将内存中的该数据移除。

图中应用阶段步骤详细介绍如下:

  1. 对3D场景中的基本场景数据(包括物体,光源,摄像机,阴影等信息)进行设置。
  2. 加速算法,粗粒度剔除,剔除摄像机无法看见的物体和光照。
  3. 设置渲染状态和参数,包括设置物体的顺序,渲染目标,渲染模式,例如物体使用的纹理,着色器,材质信息等。
  4. 调用Draw Call,输出渲染图元到显存中。

GPU流水线

概述

在CPU调用Draw Call命令GPU进行渲染,GPU渲染过程就是GPU流水线。

GPU通过实现流水化,大大加快了渲染速度(实际上GPU这种并行计算的能力不仅仅应用在渲染中,例如AI,物理模拟等都有大佬通过GPU实现优化),但是开发者无法拥有GPU的绝对控制权,只能通过GPU开放的接口进行操作。

下面介绍在GPU中进行的阶段:

几何阶段

图中几何阶段步骤详细介绍如下:

  1. 顶点着色器(完全可编程),输入的信息来自CPU输出的顶点信息,处理单位为顶点,注意顶点着色器不能创建或者删除顶点,也无法得知顶点之间的关系。
    顶点着色器会对每个输入的顶点进行编程描述的操作,剔除不可见的顶点,再对顶点进行空间变化,并自动对顶点数据进行插值,最终输出裁剪空间下的顶点信息。
  2. 可选顶点操作:

    1. 曲面细分着色器,细分网格,增加顶点
    2. 几何着色器,执行逐图元的着色操作或通过给定的图元生成更多的图元(比如Unity的粒子系统,原本只是给了粒子的一个顶点位置,但它会生成一个四边形,即两个三角形)
  3. 投影,将裁剪空间转换到标准设备坐标系(NDC,不同的图像编程接口例如OpenGL或DirectX,NDC的Z轴坐标范围不同,OpenGL的z分量为[-1,1],DirectX的Z分量为[0,1])。
  4. 裁剪,会剔除在标准坐标系外的顶点,如果物体部分在坐标系外,会对视野外的顶点剔除,并生成新的顶点。
  5. 屏幕映射,将标准坐标系转换到屏幕坐标系(不同的图像编程接口屏幕坐标系原点位置不同,OpenGL在左下方,D3D在左上方)。

光栅化阶段

图中光栅化阶段步骤详细介绍如下:

  1. 三角形设置,根据几何阶段输出的顶点屏幕位置信息,计算三角形边界信息。
  2. 三角形遍历(获取片元),根据上述边界信息获取被三角形覆盖的所有片元,片元不等同于像素,一个像素可能对应多个片元,根据之后的操作来判断是否保留、混合、舍弃该片元。

部分抗锯齿算法例如SSAA(将一个像素分为4份子样本从而提高采样率),MSAA是在光栅化阶段使用的,

逐片元操作

  1. 片元着色器(完全可编程),对光栅化阶段后得到的所有片元进行片元着色器编程描述的操作。
  2. 颜色混合阶段

    1. 透明度测试(透明度阈值)。
    2. 模板测试,其中模板测试通常用于限制区域,轮廓渲染,渲染阴影。
    3. 深度测试(测试深度)。
  3. 混合,根据之前片元着色和各种测试计算的结果,得到最终展示在屏幕的像素。

后处理

后处理步骤实际上应该不算在渲染流水线的工序,它的基本逻辑是通过对渲染流水线输出的2D图像进行再加工,例如炫光(Bloom),抗锯齿(FXAA/TXAA)等等后处理。

参考

  1. 《【技术美术百人计划】图形 1.1 渲染流水线》
  2. 《Shader入门精要》