实时渲染学习(六)延迟渲染(Deferred Rendering)
参考博文【《Real-Time Rendering 3rd》 提炼总结】(七) 第七章续 · 延迟渲染(Deferred Rendering)的前生今世
前言
本章知识概览:
- 延迟着色/延迟渲染的概念 Deferred Shading / Deferred Rendering
- 几何缓冲区 G-buffer
- 延迟渲染的渲染过程
- 延迟渲染 vs 正向渲染
- 延迟渲染的优缺点
- 延迟光照 Light Pre-Pass / Deferred Lighting
- 分块延迟渲染 Tile-Based Deferred Rendering
- 延迟渲染 vs 延迟光照
- 实时渲染中常见的Rendering Path总结
- 环境映射 Environment Mapping
一、延迟渲染 Deferred Rendering
众所周知,前向渲染(正向着色)的基本流程是先进行着色,再进行深度测试。这种方法需要对每个光源下每个需要渲染的片段进行迭代,如果旧片段被新片段覆盖(不用于最后显示),那么其着色计算就被浪费了。简言之,其缺点是光照计算与场景复杂度和光源个数紧密相关(n个物体,m个光源,复杂度O(m*n))。
为解决上述问题,提出延迟渲染(在场景中存在大量光源的情况尤为适用)。延迟渲染先将所有物体绘制到屏幕空间的缓冲(即G-Buffer,几何缓冲区)中,在逐光源对该缓冲区进行着色的过程,避免了因深度测试而丢弃的片元着色所产生的不必要的开销。简言之,延迟渲染先进行深度测试,再进行着色计算,将三维空间的光照计算转换到二维空间进行处理(复杂度O(m+n))。
前向渲染与延迟渲染的对比:
- 前向渲染,先执行着色计算,再执行深度测试,时间复杂度为O(m*n),光源数量对计算复杂度影响巨大。
- 延迟渲染,先执行深度测试,再执行着色计算,复杂度O(m+n),将光源数目与场景中物体数目在复杂度层面上完全分开,即时间复杂度不会随光源数目的变化而产生巨大变化。
二、几何缓冲区 G-Buffer
存储每个像素对应的位置、法线、漫反射颜色以及其他相关材质参数,根据这些信息,可以在二维空间中对每个像素进行光照计算。
三、延迟渲染的过程分析
延迟渲染可分为两个过程:
- 几何处理阶段:获取对象的各种几何信息,并将第二步所需的各种数据存储到多个G-Buffer中(此阶段填充G-Buffer非常高效,直接存储位置、颜色、发线等信息到帧缓存);
- 光照处理阶段:仅需渲染一个屏幕大小的二维矩形。使用G-Buffer中存储的数据对此二维矩阵的每一个片段计算场景的光照(光照计算过程与正向渲染一样,不同在于从G-Buffer中获取输入变量,而不是从顶点着色器获取)。
四、延迟渲染的优缺点
4.1 延迟渲染的优点
- 复杂度不会随光源数目变化而产生巨大变化(O(n+m));
- 只渲染可见的像素,节省计算量。
- 用更少的shader。
- 对后处理支持良好。
- 在大量光源的场景优势尤其明显。
4.2 延迟渲染的缺点
- 内存开销较大。
- 读写G-buffer的内存带宽用量是性能瓶颈。
- 对透明物体的渲染存在问题。在这点上需要结合正向渲染进行渲染。
- 对多重采样抗锯齿(MultiSampling Anti-Aliasing, MSAA)的支持不友好,主要因为需开启MRT。
五、延迟渲染的改进
- 延迟光照 Light Pre-Pass(即Deferred Lighting):将存取的G-Buffer数据结构最小化;
- 分块延迟渲染 Tile-BasedDeferred Rendering:将多个光照组成一组,以组为处理单元。
5.1 延迟光照 LightPre-Pass / Deferred Lighting
基本思路:
-
渲染场景中不透明几何体。将法线向量n和镜面扩展因子(specular spread factor)m 写入n/m-buffer 缓冲区(类似 G-Buffer,更轻量,不需要MRT支持)。
-
渲染光照。计算漫反射和镜面着色方程,并将结果写入不同的漫反射和镜面反射累积缓冲区。这个过程可以在一个单独的pass中完成(使用MRT),或者用两个单独的pass。环境光照明可以在这个阶段使用一个 full-screen pass进行计算。
-
对场景中的不透明几何体进行第二次渲染。从纹理中读取漫反射和镜面反射值,对前面步骤中漫反射和镜面反射累积缓冲区的值进行调制,并将最终结果写入最终的颜色缓冲区。若在上一阶段没有处理环境光照明,则在此阶段应用环境光照明。
-
使用非延迟着色方法渲染半透明几何体。
流程图:
总结:首先渲染不透明几何体但不渲染光照,然后对不透明几何体进行二次渲染时加入光照信息,再使用非延迟方法渲染不透明几何体,可以对每个不同的几何体使用不同的shader渲染,因此物体的材质属性将有更多的变化。
5.2 分块延迟渲染 Tile-BasedDeferred Rendering
延迟渲染的瓶颈在于在大量光源下,每个光源对 G-buffer的读取及与颜色缓冲区(color buffer)混合。由于每个光源是在不同的绘制中进行,因此光源影响范围在屏幕空间上有重疉,会重复读取G-buffer中相同位置的数据,计算后以相加混合方式写入颜色缓冲。光源越多,内存带宽用量越大。
分块延迟渲染(又称为光源剔除,通常在compute shader中实现)将屏幕划分成细小栅格,以固定像素块作为一个分块(tile),计算影响每个分块的光源索引存储在光源列表里,在逐分块进行着色时,对每像素读取G-Buffer和光源列表里相关的广源信息。这种方法使得G-Buffer的数据仅会被读取1次,ColorBuffer仅会被写入1次。
(计算着色器 Compute Shader 相关介绍)
六、环境映射
Environment mapping(环境映射),又称Reflection Mapping(反射映射),使用基于图像的光照(Image-Based Lighting,IBL)技术,用预先计算的纹理图像模拟复杂镜面的一种高效方法。
由于是事先准备好的数据,这种实现方法比传统的光线跟踪算法效率更高,但是需要注意的是这种方法是实际反射的一种近似,有时甚至是非常粗糙的近似。这种技术的一个典型的缺点是没有考虑自反射,即无法看到物体反射的物体自身的某一部分。
环境映射的常见类型有:
- 球型环境映射 Sphere Environment Mapping
- 立方体环境映射 Cubic Environment Mapping
- 抛物线环境映射 Parabolic Environment Mapping
环境映射的一些引申:
- 光泽反射环境映射(Glossy Reflections from Environment Maps)
- 基于视角的反射映射(View-Dependent Reflection Maps)
- 辐照度环境映射 (Irradiance Environment Mapping)
后记
通过本章的学习对延迟渲染的流程、优缺点以及改进有了更进一步的认识,在本章学习中看到提到了计算着色器Compute Shader相关内容,这个是OpenGL4.3的新特性,之前几乎没有接触过,Compute Shader和CUDA均是用于并行计算的,那么两者的区别又是什么呢?