渲染路径决定光照的实现方式。简言之,就是当前渲染目标使用光照的流程。
在渲染每一帧时,每个顶点/片元都要执行一次片元着色器代码,这时需要将所有的光照信息都传递到片元着色器中。虽然大部分情况下的光源都趋向于小型化,而其照亮的区域也不大,但即便是光源离这个像素所对应的世界空间中的位置很远,但计算光照时,还是会把所有的光源都考虑进去,而这样必然导致许多的浪费。
例如,物体受n个光源影响,那么在每一个片元执行着色器代码时,都必须吧这n个光源都传递进着色器中执行光照计算。
简而言之,前向渲染有以下几个规则:
规则一:最亮的几个光源会被实现为像素光照
规则二:然后最多4个光源会被实现为顶点光照
规则三:剩下的光源会被实现为效率较高的球面调谐光照(Spherical Hamanic),这是一种模拟光照
规则一补充说明:
Unity的Frame Debug很容易看出前向渲染的过程,正如上述规则描述的一样
将渲染过程拆分成两个渲染通路(pass)。
第一个pass称为几何处理通路。首先将场景渲染一次,获取到待渲染对象的各种几何信息存储到名为G-buffer的缓冲区中,这些缓冲区将会在之后用作更复杂的光照计算。由于有深度测试,所以最终写入G-buffer中的各个数据都是离摄像机最近的片元的几何属性,这意味着最后在G-buffer中的片元必定要进行光照计算的。
第二个pass称为光照处理通路。该pass会遍历所有G-buffer中的位置、颜色、法线等参数,执行一次光照计算。
G-Buffer,全称Geometric Buffer ,译作几何缓冲区,它主要用于存储每个像素对应的位置(Position),法线(Normal),漫反射颜色(Diffuse Color)以及其他有用材质参数。根据这些信息,就可以在像空间(二维空间)中对每个像素进行光照处理。
简单的说,延迟渲染实际上可以看作是一个后处理,只不过在后处理之前,它把所有需要的信息都已经拿到了,这些信息都分别存储在一张自己的RT中,而所有RT都存储在G-Buffer中,同时也因为这样,所以延迟渲染对许多后处理的支持非常好。
1、支持半透明渲染
2、支持使用多个光照pass
3、支持自定义光照计算方式
1、光源数量对计算复杂度影响巨大
2、访问深度等数据需要额外计算
1、大量光照场景优势明显
2、只渲染可见像素,节省计算量
3、对后处理支持良好
4、用更少的shader
1、对MSAA支持不友好(因为G-Buffer存储的是已经光栅化了的片元,无法细分)
2、透明物体渲染存在问题 (因为G-Buffer保留的都是离相机最近的片元,深度会有问题,渲染透明物体只能使用前向渲染的方式向渲染)
3、占用大量的显存带宽 (存储G-Buffer)
Tile-Based Deferred Rendering,简称TBDR,意思是分块延迟渲染,这里指的是SIGGRAPH 2010上提出的,通过分块来降低带宽内存用量,它计算每个分块的深度范围(depth range),求得每个 tile 的 包围盒bounding box。然后,计算每个分块的包围盒bounding box会受到哪些光源影响,把那些光源的索引储存在分块的光源列表里。最后,逐个分块进行着色,对每像素读取 G-buffer 和光源列表及相关的光源信息。因此,G-buffer的数据只会被读取1次且仅1次,写入 color buffer也是1次且仅1次,大幅降低内存带宽用量。不过,这种方法需要计算光源会影响哪些分块,这个计算又称为光源剔除(light culling),可以在 CPU 或 GPU(通常以 compute shader 实现)中进行。用GPU计算的好处是,GPU 计算这类工作比 CPU 更快,也减少 CPU/GPU 数据传输。而且,可以计算每个分块的深度范围(depth range),作更有效的剔除。
对比 Deferred Rendering,之前是对每个光源求取其作用区域 light volume,然后决定其作用的的 pixel,也就是说每个光源要求取一次。而使用 TBDR,只要遍历每个 pixel,让其所属 tile 与光线求交,来计算作用其上的 light,并利用 G-Buffer 进行 Shading。一方面这样做减少 了所需考虑的光源个数,另一方面与传统的 Deferred Rendering 相比,减少了存取的带宽。
(另一个是PowerVR基于手机GPU的TBR架构提出的,通过HSR减少overdraw,见[自学记录03|百人计划]移动端GPU的TB(D)R架构基础__Yhisken的博客-CSDN博客)
减少G-buffer占用的过多开销,支持多种光照模型
和延迟渲染的区别:用更少的buffe信息,着色计算的时候用的是forward,所以第三步开始都是前向渲染(可以对不同的物体进行不同的光照模型)
减少带宽,支持多光源,强制需要一个preZ
通过分块索引的方式,以及深度和法线信息来到需要进行光照计算的片元进行光照计算。需要法线和深度的后处理需要单独渲染一个rt出来。强制使用了一个preZ,进行了一个深度预计算。
在传统前向渲染基础上添加了一个基于计算着色器的光源剔除阶段(light-culling),使得使用前向渲染更多光源变得可能。可以参考这位大佬写的Forward+ Shading - 知乎 (zhihu.com)
群组渲染的主要思路也是对光源进行剔除,可以看做是分块渲染的一个升级版。分块渲染的思路是对每一个图块进行光源剔除,而群组渲染的思路则更加简单粗暴,在分块渲染的基础上,在深度方向也进行多次分层。使得带宽相对减少,多光源下效率提升。
更多可以参考:渲染路径(Rendering Path)与常见渲染技术 - 知乎 (zhihu.com)
3400_哔哩哔哩_bilibili
3400延迟渲染 (qq.com)
Real-Time Rendering笔记(6):正向渲染和延迟渲染 - 知乎 (zhihu.com)
渲染路径(Rendering Path)与常见渲染技术 - 知乎 (zhihu.com)
Forward+ Shading - 知乎 (zhihu.com)