浅谈渲染流水线
本文将介绍渲染流水线
渲染流水线简介
渲染流水线字面意思就是渲染的流水线,它将渲染的流程分成一个个工序,每个工序会不间断地对没有完成该工序的对象进行处理,这样所有对象都会并行地进行渲染流程,提高了单位时间内的生产量,而性能的瓶颈也将由耗时最长的工序决定。
渲染管线最终的目的就是为了将场景中的3D元素转换为屏幕上的2D图像,输出到用户的屏幕上
下图是在《【技术美术百人计划】图形 1.1 渲染流水线》讲解的PPT里面截的图片,相较于《Shader入门精要》更为详细:
第一张截图为简单版:
第二张截图为详细版:
接下来详细介绍每个阶段的具体操作。
各阶段详细介绍
CPU阶段
应用阶段
应用阶段是所有阶段中唯一在CPU中执行的,它会将渲染所需要的数据从硬盘加载到内存中,再调用Draw Call命令将网格和纹理等数据转换成渲染图元,并加载到显存中,因为显卡访问显存得更快,而且大部分显卡对于内存没有直接的访问权限。
Draw Call实际上就是一个命令,CPU发起,GPU接收,命令指向一个图元列表,GPU根据渲染状态和所有输入的顶点数据进行计算,最终输出到屏幕。
加载到显存后且CPU不会再访问的数据(例如有时可能需要使用网格计算碰撞则需要CPU访问网格数据)会将内存中的该数据移除。
图中应用阶段步骤详细介绍如下:
- 对3D场景中的基本场景数据(包括物体,光源,摄像机,阴影等信息)进行设置。
- 加速算法,粗粒度剔除,剔除摄像机无法看见的物体和光照。
- 设置渲染状态和参数,包括设置物体的顺序,渲染目标,渲染模式,例如物体使用的纹理,着色器,材质信息等。
- 调用Draw Call,输出渲染图元到显存中。
GPU流水线
概述
在CPU调用Draw Call命令GPU进行渲染,GPU渲染过程就是GPU流水线。
GPU通过实现流水化,大大加快了渲染速度(实际上GPU这种并行计算的能力不仅仅应用在渲染中,例如AI,物理模拟等都有大佬通过GPU实现优化),但是开发者无法拥有GPU的绝对控制权,只能通过GPU开放的接口进行操作。
下面介绍在GPU中进行的阶段:
几何阶段
图中几何阶段步骤详细介绍如下:
- 顶点着色器(完全可编程),输入的信息来自CPU输出的顶点信息,处理单位为顶点,注意顶点着色器不能创建或者删除顶点,也无法得知顶点之间的关系。
顶点着色器会对每个输入的顶点进行编程描述的操作,剔除不可见的顶点,再对顶点进行空间变化,并自动对顶点数据进行插值,最终输出裁剪空间下的顶点信息。 可选顶点操作:
- 曲面细分着色器,细分网格,增加顶点
- 几何着色器,执行逐图元的着色操作或通过给定的图元生成更多的图元(比如Unity的粒子系统,原本只是给了粒子的一个顶点位置,但它会生成一个四边形,即两个三角形)
- 投影,将裁剪空间转换到标准设备坐标系(NDC,不同的图像编程接口例如OpenGL或DirectX,NDC的Z轴坐标范围不同,OpenGL的z分量为[-1,1],DirectX的Z分量为[0,1])。
- 裁剪,会剔除在标准坐标系外的顶点,如果物体部分在坐标系外,会对视野外的顶点剔除,并生成新的顶点。
- 屏幕映射,将标准坐标系转换到屏幕坐标系(不同的图像编程接口屏幕坐标系原点位置不同,OpenGL在左下方,D3D在左上方)。
光栅化阶段
图中光栅化阶段步骤详细介绍如下:
- 三角形设置,根据几何阶段输出的顶点屏幕位置信息,计算三角形边界信息。
- 三角形遍历(获取片元),根据上述边界信息获取被三角形覆盖的所有片元,片元不等同于像素,一个像素可能对应多个片元,根据之后的操作来判断是否保留、混合、舍弃该片元。
部分抗锯齿算法例如SSAA(将一个像素分为4份子样本从而提高采样率),MSAA是在光栅化阶段使用的,
逐片元操作
- 片元着色器(完全可编程),对光栅化阶段后得到的所有片元进行片元着色器编程描述的操作。
颜色混合阶段:
- 透明度测试(透明度阈值)。
- 模板测试,其中模板测试通常用于限制区域,轮廓渲染,渲染阴影。
- 深度测试(测试深度)。
- 混合,根据之前片元着色和各种测试计算的结果,得到最终展示在屏幕的像素。
后处理
后处理步骤实际上应该不算在渲染流水线的工序,它的基本逻辑是通过对渲染流水线输出的2D图像进行再加工,例如炫光(Bloom),抗锯齿(FXAA/TXAA)等等后处理。
参考
- 《【技术美术百人计划】图形 1.1 渲染流水线》
- 《Shader入门精要》