图形 3.4 延迟渲染管线介绍

延迟渲染管线介绍

B站视频:图形 3.4 延迟渲染管线介绍

渲染路径

渲染路径(Rendering Path),决定光照的实现方式。简言之,就是当前渲染目标使用光照的流程。

  • 前向渲染(Forward Rendering)
  • 延迟渲染(Defferred Rendering)

前向渲染

发生在渲染管线的顶点处理阶段,会计算所有的顶点的光照。全平台支持。

渲染流程

在这里插入图片描述

待渲染几何体 → 顶点着色器 → 片元着色器 → 渲染目标

在渲染每一帧时,每个顶点/片元都要执行一次片元着色器代码,这时需要将所有的光照信息都传递到片元着色器中。虽然大部分情况下的光源都趋向于小型化,而其照亮的区域也不大,但即便是光源离这个像素所对应的世界空间中的位置很远,但计算光照时,还是会把所有的光源都考虑进去

例如,物体受n个光源影响,那么在每一个片元执行着色器代码时,都必须把这n个光源都传递进着色器中执行光照计算。

在这里插入图片描述

光照规则

  • 规则一:最亮的几个光源会被实现为像素光照;
  • 规则二:然后最多4个光源会被实现为顶点光照;
  • 规则三:剩下的光源会被实现为效率较高的球面调谐光照(Spherical Hamanic),这是一种模拟光照。

规则一补充说明:

  • 最亮的那盏光一定是像素光照;
  • Light的Render Mode是important的光一定是像素光照;
  • 如果前面的两条加起来的像素光照小于Quality Setting里的Pixel Light Count(最大像素光照数量),那么从剩下的光源中找出最亮的那几盏光源,实现为像素光照;
  • 最后剩下的光源,按照规则二或规则三 ;
  • 在base pass里执行一盏像素光、所有的顶点光和球面调谐光照,并且进行阴影计算;
  • 其余的像素光每盏一个Additional Pass,并且这些pass里没有阴影计算;
  • 场景中看到的阴影,全是base pass里计算出最亮那盏像素光的阴影,其他像素光是不计算阴影的。

延迟渲染

延迟渲染(Deferred Rendering),主要解决大量光照渲染的方案

延迟渲染的实质,是先不要做迭代三角形做光照计算,而是先找出来能看到的所有像素再去迭代光照。直接迭代三角形的话,由于大量三角形你是看不到的,无疑是极大的浪费。

渲染流程

在这里插入图片描述

待渲染几何体 → 顶点着色器 → MRT → 光照计算 → 渲染目标

将渲染过程拆分成两个渲染通路(pass)。

第一个pass称为几何处理通路。首先将场景渲染一次,获取到待渲染对象的各种几何信息存储到名为G-buffer的缓冲区中,这些缓冲区将会在之后用作更复杂的光照计算。由于有深度测试,所以最终写入G-buffer中的各个数据都是离摄像机最近的片元的几何属性,这意味着最后在G-buffer中的片元必定要进行光照计算的。

第二个pass称为光照处理通路。该pass会遍历所有G-buffer中的位置、颜色、法线等参数,执行一次光照计算。

在这里插入图片描述

几何缓冲区 G-buffer

G-Buffer,全称Geometric Buffer ,译作几何缓冲区,它主要用于存储每个像素对应的位置(Position),法线(Normal),漫反射颜色(Diffuse Color)以及其他有用材质参数。根据这些信息,就可以在像空间(二维空间)中对每个像素进行光照处理。

在这里插入图片描述

不同渲染路径的优劣以及特性

  • 后处理方式不同

    假设需要深度信息来进行后处理,前向渲染就需要单独渲染出一张深度图,而延迟渲染就可以直接用G-Buffer里面的深度来进行计算。

  • 着色计算不同

    由于延迟渲染光照计算统一是在Light Pass中计算的,所以只能算一个光照模型,如果需要用到其他的光照模型,只能切换Pass。

在这里插入图片描述

  • 抗锯齿方式不同

优劣

渲染方式/优劣优点缺点
前向渲染1. 支持半透明渲染;
2. 支持使用多个光照pass;
3. 支持自定义光照计算方式。
1. 光源数量对计算复杂度影响巨大;
2. 访问深度等数据需要额外计算。
延迟渲染1. 大量光照场景优势明显;
2. 只渲染可见像素,节省计算量;
3. 对后处理支持良好;
4. 用更少的shader。
1. 对MSAA支持不友好;
2. 透明物体渲染存在问题;
3. 占用大量的显存带宽。

Unity中渲染路径设置

版本为2022.3.5f1c1

在这里插入图片描述

在这里插入图片描述

移动端优化

常见的架构有三种:IMR,TBR和TBDR。其中IMR用于PC端的GPU渲染,TBR用于移动端,TBDR是基于TBR的改进。

IMR

如下所示,这是传统的IMR架构(Immediate Mode Rendering)。

在这里插入图片描述

蓝色部分为渲染管线,灰色部分为GPU的显存,包括几何信息、纹理信息、深度buffer及Frame Buffer等

  • 渲染管线里的读写操作都是直接在显存和GPU中传输数据的,比如说上图中灰色和蓝色之间交互的箭头,向上的箭头表示读取,向下的箭头表示写回;
  • 每一次渲染完的Color和Depth数据写回到Frame Buffer和 Depth Buffer都会产生很大的带宽消耗,所以IMR架构中也会有L1和L2之类的Cache来优化这部分大量的带宽消耗。

该架构在在移动平台上的应用主要存在两个问题:

  • 计算力的浪费

    当两次渲染有前后遮蔽关系时,IMR模式因为两次draw命令都要执行,因此会存在经过片断着色后的像素被深度测试抛弃,这样就浪费了GPU的运算能力。当然,目前几乎所有的IMR架构的GPU都会提供Early Z的判断方式,一般是在光栅化里面对图形的遮蔽关系进行判断,提前剔除被遮挡像素,避免它在像素着色器中的计算。

  • 带宽的浪费

    渲染命令在执行需要随时读写frame buffer,depth buffer和stencil buffer,这带来大量的内存带宽消耗,在移动平台上面访问片外内存是最消耗电量和最耗时的操作,带宽的消耗带来的结果就是耗电的提高。

TBR

在移动端,由于没有属于GPU的独立显示, Framebuffer将会存储在主存中,这时候所有跟Framebuffer 进行的读写操作就需要跟主存进行频繁的数据传输,这样在性能和功耗上都是难以接受的,于是解决办法就是在 GPU上做一块片上Cache,大小虽然无法存储整个Framebuffer,但是足够存储一个Tile 的内容,这样一来所有数据读写都在这块Tile上进行,以达到节省带宽降低功耗的目的。这就是TBR(Tile Based Rendering)架构的基础,如下图所示:

在这里插入图片描述

渲染过程有分为两个阶段:

  • tiling

    它将需要渲染的画面分成一个个的矩形区块,例如16x16。模型的顶点经过顶点着色器运算以后会组装成一个个的三角形,这些三角形会被缓存在一个三角形缓存中。如果某个三角形需要在某个区块里面绘制,那么就会在该区块的三角形列表中存一个索引。等一帧里面所有的渲染命令都经执行顶点着色器后,每个tile就会有一个三角形列表,这列表就包含了需要在该tile内部绘制的所有三角形

  • rasterization and fragment processing

    进行光栅化和片段计算。

TBR的优点是:节约带宽。

执行raster和Per-fragment operation时不需要反复的访问frame buffer,depth buffer,stencil buffer。这是因为GPU可以把整个tile的frame buffer/depth buffer/stencil buffer保存在一个片上的高速缓存中,这样GPU就直接访问tile,而不需要访问外部内存。这大大减少了内存的带宽消耗,也意味着能耗的降低。

TBR的缺点是:需要保存顶点着色器执行后的结果以及每个tile的三角形列表。

这意味着如果场景里面有很多的顶点,那么片上缓存就不可能存下这么多顶点信息和三角形列表,就不得不依靠外部内存来存储,就会有额外的带宽消耗。不过庆幸的是当前的移动3D绘制都不会有太多三角形的场景。一个复杂的模型也就1万多个三角形,因此一个通常的场景大概就是几十万三角形。随着移动游戏越来越复杂精美,模型的复杂程度也会快速上升,这也是TBR架构在未来将会面临的一大挑战。

如果在一帧里面有两遍及其以上的渲染,那么就需要使用Framebuffer object来缓存中间结果,这对TBR又是一大性能损耗。根据我们前面的讲解,TBR需要缓冲一帧所有的图元,所有图元执行完毕后才开始raster和Per-fragment operation。在这种情况下,一旦后面的draw命令需要使用到前面渲染生成的结果,那么就不得不在该命令执行前,要求GPU把缓存的所有draw命令都执行完毕,然后放弃当前缓存内容。在极端情况下,例如每次draw都需要读取前一次draw渲染的结果,那么TBR就会直接退化成IMR模式。

每个tile数据会存储在高速缓存上,称为On-Chip Memory。不同的GPU对高速缓存有不同的命名,例如apple gpu的threadgroup memory,adreno gpu的gmem,mali gpu的tile buffer。

TBDR

作为传统Defferred Rendering的另一种主要改进,分块延迟渲染(Tile-Based Deferred Rendering,TBDR)旨在合理分摊开销(amortize overhead),自SIGGRAPH 2010上提出以来逐渐为业界所了解。

我们知道,延迟渲染的瓶颈在于读写 G-buffer,在大量光源下,具体瓶颈将位于每个光源对G-buffer的读取及与颜色缓冲区混合。这里的问题是,每个光源,即使它们的影响范围在屏幕空间上有重叠,因为每个光源是在不同的绘制中进行,所以会重复读取G-buffer中相同位置的数据,计算后以相加混合方式写入颜色缓冲。光源越多,内存带宽用量越大。

而分块延迟渲染的主要思想则是把屏幕分拆成一个个小的分块,例如每 32 × 32 像素作为一个分块(tile)。计算每个分块的深度范围(depth range),求得每个 分块的包围盒(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 相比,减少了存取的带宽。

在这里插入图片描述

其他渲染路径

  • 延迟光照 (Light Pre-Pass / Deferred Lighting)

    减少G-buffer占用的过多开销,支持多种光照模型。

  • Forward+(Tiled Forward Rendering,分块正向渲染)

    减少带宽,支持多光源,强制需要一个preZ。

  • 群组渲染(Clustered Rendering)

    带宽相对减少,多光源下效率提升。

具体请参考游戏引擎中的光照算法 - 知乎

不同路径下光源shader编写

在这里插入图片描述

参考资料

Real-Time Rendering笔记(6):正向渲染和延迟渲染 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值