实时图形渲染管线流程概述(理解向)
渲染管线概述
本文用于记录与整理实时渲染管线的流程,参考GAMES101,GAMES104,技术美术百人计划
实时图形渲染管线是一系列输入输出组合而成的流水线,即输入顶点数据,得到屏幕上显示的图像,这个过程中会经历很多操作来使得计算机能够实时的将图像合理的显示在屏幕上
很喜欢GAMES101里的一句话,我们往往会更关注what和why,而how是最不重要的地方
因此本文会注重WHAT与WHY,具体的HOW会以超链接形式插入(陆续补充…)
目录
整体流程
阶段 | 内容 |
---|---|
应用阶段: | 粗颗粒剔除, 渲染设置, 准备基本数据, 输出到几何阶段 |
几何阶段: | 顶点着色器, 曲面细分, 几何着色器, 顶点裁剪, 屏幕映射 |
光栅化阶段: | 三角形设置, 三角形遍历, 片段着色器 |
逐片元操作: | 裁剪测试, 透明度测试, 深度测试, 模板测试, 混合 |
后处理: | 泛光 边缘检测 模糊 景深 HDR FXAA |
具体流程
渲染管线相当于一个流水线车间,加工产品是数据,磁盘上的数据会经过 cpu->gpu 这2个车间,最终加工成屏幕上像素点中的色彩信息
CPU(应用阶段)
1.数据的读取
我们的模型与贴图是存储在磁盘上的,这些数据是其他软件的加工品如3dmax,maya,blender等,里面存储着顶点,法线,uv等等我们常见的信息,当然也包含着一些为了更好的效果或者是更快的速度为软件所独有一些信息,这一部分信息是无法被有效利用的.
这些数据经过规整化(不同软件可能有着不同的数据定义方式),剔除掉不可用的数据,加载到了内存上以待进一步的处理.
2.准备基本数据
对于需要渲染的数据进行准备
- 场景物体数据
- 物体的变换数据(位置,缩放,旋转等)
- 物体的网格数据(顶点,贴图,法线,切线等)
- 光源数据
- 光源类型(方向光,点光,聚光等)
- 光源的位置,角度,方向,颜色等
- 摄像机数据
- 位置,方向,远近裁剪平面等
- 正交/透视模式
- 屏幕尺寸/比例等
3.光源与阴影
- 设置光源
- 方向光:颜色,方向等
- 点光:颜色,位置,范围等
- 聚光:颜色,位置,方向,内外圆锥角等
- 设置阴影
- 是否需要阴影
- 阴影参数:对应光源,阴影强度,级联参数,深度偏移,近平面偏移等
- 逐光源绘制阴影贴图
- 近平面偏移
- 逐级联
- 计算当前光源+级联对应的观察矩阵、投影矩阵、阴影贴图的视口区域
- 绘制到阴影贴图
4.加速算法
- 可见光裁剪:裁剪掉距离过远,光线与视锥不相交的光源
- 场景物体裁剪:裁剪被遮挡,不在视锥范围内的物体
- 八叉树
- BSP树
- K-D树
- BVH包围盒
5.渲染设置
- 绘制设置
- 使用不同着色器
- 合批方式(动态,静态批处理,GPU instance)
- 绘制物体的顺序
- 相对摄像机的距离
- 材质RenderQueue
- UICanvas
- 渲染目标
- FrameBuffer
- RenderTexture
- 渲染模式
- 前向渲染
- 延迟渲染
6.输出到显存
将之前处理好的顶点数据和其他数据如(mvp变换矩阵,纹理贴图等)按照渲染设置输出到GPU
GPU
GPU基础架构
GPU如图所示可以简单的划分为3个层级,
- GPU: 如图左下侧所示,主要由SM,DRAM(显存),L2(二级缓存)组成
- GPC: 图形处理集群,一个GPU有多个GPC,一个GPC包含多个SM
- SM: 计算单元,一个GPU有多个SM,每个SM如图右侧所示
- Texture Units: 纹理处理单元,可以提取和过滤纹理
- Core: 允许不同处理器同时处理数据的并行处理器
- Warp: 在SM里面将SP(thread)进行分组,一般每32个thread称为一个warp
LD/ST:load/store,用于内存操作的,读取单元。
SFU:special function unit,来执行超指令(transcendental instruction)如正弦、余弦、倒数和平方根等函数。每个 SFU 一次执行一个线程块中一个线程的一条指令
SIMD 与SIMT
SIMD (Single Instruction Multiple Data)
- 单指令处理多数据,处理单元可以同时对多个数据点执行相同的操作(如向量加法)
SIMT (Single Instruction Multiple Threads)
- 单指令处理多线程,并行计算中使用的一种执行模型,将单指令多数据(SIMD)与多线程结合在一起
7.几何阶段
- 顶点着色
- 视图变换(MVP)
- 顶点着色
- 曲面细分着色器->几何着色器
- 曲面细分
- 几何着色
- 投影
- 除以w将投影坐标系转换到NDC标准坐标系
- 裁剪
- 视锥体裁剪(CVV)
- 正面背面剔除
- 屏幕映射
- 视口转化(xy分别映射到WH,z映射到远近平面,平移+缩放)
8.光栅化阶段
- 三角形设置(计算三角形/直线边界信息,图元装配)
- 三角形遍历(检查像素是否被三角形覆盖,若在三角形内计算插值,更新深度)
- 抗锯齿(MSAA,SSAA,FXAA/TXAA(后处理))
9.逐片元操作
- 片段着色
- 颜色混合
- 透明度测试(alpha test)
- 深度测试()
- 模板测试()
- 目标缓冲区
10.后处理
- 泛光
- 边缘检测
- 模糊
- 景深
- HDR
- FXAA
…
总结
渲染管线是一个复杂的流水线, 理解起来会有很多误区, 这里简单的介绍了一下通用的渲染管线以加深理解.如果以一个顶点的一生来描述渲染管线的话:
- 应用
存储在磁盘上的顶点A被选择有效数据后加载到内存上,cpu对他的同胞数据进行了各种处理,处理结果会最终作用到自己身上,顶点A被识别为三角形的一员送入了GPU; - 几何
GPU中顶点A经历了模型矩阵,视口矩阵,投影矩阵的变换;模型被细分后加入了许多新顶点,顶点A随之进行了位置的调整,加入了新的三角形中;顶点A除以自身的w后被转换到了一个以原点为中心向各轴延展1的正方形空间中,没有被划分进来的顶点被裁剪掉了,划分了一半的三角形为了维持形状新增了新的顶点进行补全,根据三角形绘制时针方向判断正反面,不该被渲染的面也被剔除掉了,顶点A再次转换到了屏幕空间中(0-W,0-H,Near-Far),顶点A覆盖了像素B,接下来就是像素B的一生了 - 光栅化
像素B是顶点A在其坐标所对应的像素,但他属于许多三角形,三角形通过顶点的插值决定了三角形在像素B上的数据,像素B要根据深度测试,alpha测试等判断是否要采用三角形的数据,同样应用阶段的各种数据也会作用到像素B的生成上(如阴影,光照等),像素B经过各种数据的混合最终变成了屏幕上所显示的像素
补充
- 各种测试的相对顺序:裁剪->Alpha->模板->深度
- Early-Z
- Early-Z是一种提前深度测试的技术,它位于光栅化阶段之后,像素处理阶段之前,目的是减少进入像素着色阶段的片段,优化性能。Early-Z会带来透明测试的冲突,例如某个片元A虽然遮挡了另一个片元B,但A却是透明的,GPU应当渲染的是片元B,这就产生了矛盾,这就是透明度测试会导致性能下降的原因(因为无法用Early-Z),但是有一种叫PreZ的技术可以解决这个问题,参考上面的链接,不再详述。