目录
前言
P1
前向渲染
在前向渲染中,影响每个对象的一些最亮的光源以完全逐像素光照模式渲染。然后,最多 4 个点光源采用每顶点计算方式。其他光源以球谐函数 (SH) 计算,这种计算方式会快得多,但仅得到近似值。光源是否为每像素光源根据以下原则而定:
- Render Mode 设置为 Not Important 的光源始终为每顶点或 SH 光源。
- 最亮的方向光始终为每像素光源。
- Render Mode 设置为 Important 的光源始终为每像素光源。
- If the above results in fewer lights than current Pixel Light Count Quality Setting, then more lights are rendered per-pixel, in order of decreasing brightness.
每个对象的渲染按如下方式进行:
- 基础通道应用一个每像素方向光和所有每顶点/SH 光源。
- 其他每像素光源在额外的通道中渲染(每个光源对应一个通道)。
例如,如果某个对象受到许多光源的影响(下图中的圆形受光源 A 到 H 的影响):
让我们假设光源 A 到 H 具有相同的颜色和强度,并且所有光源都具有自动渲染模式,因此它们将严格按照此对象的以下顺序排序。最亮的光源将以每像素光照模式渲染(A 到 D),然后最多 4 个光源以每顶点光照模式渲染(D 到 G),最后其余光源以 SH 进行渲染(G 到 H):
请注意,光源组会重叠;例如,最后一个每像素光源混合到每顶点光照模式,因此当对象和光源移动时,“光射量”(light popping) 较少。
Base Pass
基础通道使用一个每像素方向光和所有 SH/每顶点光源来渲染对象。此通道还会添加着色器中的所有光照贴图、环境光照和发射光照。在此通道中渲染的方向光可以具有阴影。请注意,光照贴图的对象不会从 SH 光源获得光照。
请注意,在着色器中使用“OnlyDirectional”通道标志时,前向基础通道仅渲染主方向光、环境光/光照探针和光照贴图(SH 和顶点光源不包括在通道数据中)。
Additional Passes
对于影响此对象的每个额外的每像素光源,需要额外的渲染通道。默认情况下,这些通道中的光源没有阴影(因此在结果中,前向渲染支持一个带阴影的方向光),除非使用 multi_compile_fwdadd_fullshadows 变体快捷方式。
Per-pixel lights
在渲染过程中,Unity 会查找网格周围的所有光源,并计算出哪些光源对网格的影响最大。使用 Quality 窗口上的设置可修改多少个光源用于像素光照以及多少个用于顶点光照。每个光源根据它与网格的距离以及它的光照强度来计算其重要性;纯粹从游戏背景而言,有些光源比另一些光源更重要。鉴于此原因,每个光源都有 Render Mode 设置,可设置为 Important 或 Not Important__;标记为 Not Important__ 的光源具有较低的渲染开销。
Spherical Harmonics lights
球谐函数光源的渲染速度_很_快。这些光源的 CPU 成本很低,并且使用 GPU 的_成本基本为零_(也就是说,基础通道始终会计算 SH 光照;但由于 SH 光源工作方式的原因,无论 SH 光源有多少,成本都完全相同)。
SH 光源的缺点:
- 按对象的顶点而不是按像素计算。这意味着它们不支持光照剪影和法线贴图。
- SH 光照的频率很低。SH 光源无法实现快速的光照过渡。它们也只影响漫射光照(频率对镜面高光而言太低)。
- SH 光照不是局部光照;SH 点光源或聚光灯在靠近某种表面时“看起是错误的”。
延迟渲染
使用延迟着色时,可影响游戏对象的光源数量没有限制。所有光源都按像素进行评估,这意味着它们都能与法线贴图等正确交互。此外,所有光源都可以有剪影和阴影。
延迟着色的优点是,光照的处理开销与接受光照的像素数成正比。这取决于场景中的光量大小,而不管接受光照的游戏对象有多少。因此,可通过减少光源数量来提高性能。延迟着色还具有高度一致和可预测的行为。每个光源的效果都是按像素计算的,因此不会有在大三角形上分解的光照计算。
在缺点方面,延迟着色并不支持抗锯齿,也无法处理半透明游戏对象(这些对象使用前向渲染进行渲染)。此外,它也不支持网格渲染器 (Mesh Renderer) 的接受阴影 (Receive Shadows) 标志,并且仅在有限程度上支持剔除遮罩。最多只能使用四个剔除遮罩。也就是说,剔除层遮罩必须至少包含所有层减去四个任意层,即必须设置 32 个层中的 28 个层。否则,会产生图形瑕疵。
要求
- 延迟着色要求显卡具有多渲染目标 (MRT)、着色器模型 3.0(或更高版本)并支持深度渲染纹理。从 GeForce 8xxx、Radeon X2400、Intel G45 开始,2006 年以后制造的大多数 PC 显卡都支持延迟着色。
- 所有至少运行 OpenGL ES 3.0 的移动设备都支持延迟着色。
性能注意事项
- 延迟着色中实时光源的渲染开销与光源照亮的像素数成正比,不依赖于场景复杂性。因此,小点光源或聚光灯的渲染成本非常低,如果它们被场景游戏对象完全或部分遮挡,那么它们甚至更便宜。
- 当然,有阴影的光源比没有阴影的光源的成本高得多。在延迟着色中,对于每个阴影投射光源,仍然需要将投射阴影的游戏对象渲染一次或多次。此外,应用阴影的光照着色器的渲染开销高于禁用阴影时的渲染开销。
实现详细信息
如果对象的着色器不支持延迟着色,则会在延迟着色结束后使用前向渲染路径来渲染这些对象。
下面列出了 G 缓冲区中渲染目标 (RT0 - RT4) 的默认布局。数据类型放置在每个渲染目标的各个通道中。使用的通道显示在括号内。
- RT0,ARGB32 格式:漫射颜色 (RGB),遮挡 (A)。
- RT1, ARGB32 format: Specular color (RGB), smoothness (A).
- RT2,ARGB2101010 格式:世界空间法线 (RGB),未使用 (A)。
- RT3,ARGB2101010(非 HDR)或 ARGBHalf (HDR) 格式:发射 + 光照 + 光照贴图 + 反射探针缓冲区。
- 深度+模板缓冲区。
因此,默认的 G 缓冲区布局为 160 位/像素(非 HDR)或 192 位/像素 (HDR)。
如果混合光照模式为 Shadowmask 或 Distance Shadowmask,则使用第五个目标:
- *RT4,ARGB32 格式:光照遮挡值 (RGBA)。
因此,G 缓冲区布局为 192 位/像素(非 HDR)或 224 位/像素 (HDR)。
如果硬件不支持五个并发渲染目标,则使用阴影遮罩的对象将回退到前向渲染路径。 当摄像机不使用 HDR 时,发射+光照缓冲区 (RT3) 采用对数编码,因此提供的动态范围高于 ARGB32 纹理通常可能提供的范围。
请注意,当摄像机使用 HDR 渲染时,不会为发射 + 光照缓冲区 (RT3) 创建单独的渲染目标;而是将摄像机渲染到的渲染目标(即传递给图像效果的渲染目标)用作 RT3。
G 缓冲区通道
G 缓冲区通道将每个游戏对象渲染一次。漫射和镜面反射颜色、表面平滑度、世界空间法线和发射+环境+反射+光照贴图都将渲染到 G 缓冲区纹理中。G 缓冲区纹理设置为全局着色器属性供着色器以后访问(_CameraGBufferTexture0 .._CameraGBufferTexture3 指定)。
光照通道
光照通道根据 G 缓冲区和深度来计算光照。光照是在屏幕空间内计算的,因此处理所需的时间与场景复杂性无关。光照将添加到发射缓冲区。
不穿过摄像机近平面的点光源和聚光灯将渲染为 3D 形状,并启用 Z 缓冲区对场景的测试。这使得部分或完全遮挡的点光源和聚光灯的渲染成本非常低。穿过近平面的定向光源和点光源或聚光灯将呈现为全屏四边形。
如果光源启用了阴影,那么也会在此通道中渲染并应用阴影。请注意,阴影并非是“无成本”的;需要渲染阴影投射物,并且必须应用更复杂的光照着色器。
唯一可用的光照模型是标准 (Standard) 光照模型。如果需要不同的模型,可修改光照通道着色器,方法是将内置着色器中的 Internal-DeferredShading.shader 文件的修改版本放入“Assets”文件夹中名为“Resources”的文件夹内。然后打开 Graphics 设置(菜单:Edit > Project Settings,然后单击 Graphics 类别)。将“Deferred”下拉选单改为“Custom Shader”。然后,更改当前使用的着色器对应的着色器 (Shader) 选项。
P2
前向渲染优缺点
优点
- 支持半透明渲染
- 支持使用多个光照pass
- 支持自定义光照计算方式
缺点
- 光源数量对计算复杂度影响巨大
- 访问深度等数据需要额外计算(需要再渲染一张深度图)
延迟渲染优缺点
优点
- 大量光照场景的情况下,优势明显
- 只渲染可见像素,节省计算量
- 对后处理支持良好(例如深度信息:直接拿G-buffer中的就行)
- 用更少的shader(所有的物体光照模型都一样,很多东西不用再定义了)
缺点
- 对MSAA支持不友好
- 透明物体渲染存在问题(深度问题,只渲染力物体最近的物体,渲染透明度时会出现问题)
- 占用大量的显存带宽
- 涉及一个clear的操作,如果不清理的话,后边可以继续获取到
- 每一帧都需要几张rt在显存中传输、清理等,会更耗带宽
- 只能使用同一个光照pass
- 阴影仍然取决于灯光的数量,延迟渲染无法解决此问题。
其他渲染路径
延迟光照(Light Pre-Pass / Deferred Lighting)
- 减少G-buffer占用的过多开销,支持多种光照模型
- 和延迟渲染的区别:
- 用更少的buffe信息,着色计算的时候用的是forward,所以第三步开始都是前向渲染(可以对不同的物体进行不同的光照模型)
Forward+(即Tiled Forward Rendering,分块正向渲染)
- 减少带宽,支持多光源,强制需要一个preZ
- 通过分块索引的方式,以及深度和法线信息来到需要进行光照计算的片元进行光照计算。
- 需要法线和深度的后处理需要单独渲染一个rt出来
- 强制使用了一个preZ(如果没涉及过这个概念的话,可以理解为进行了一个深度预计算)
群组渲染(Clustered Rendering)
- 带宽相对减少,多光源下效率提升
- 分为forward和deferred两种
- 详细补充拓展:游戏引擎中的光照算法 - 知乎
改进方案
Unity移动端性能优化 - 知乎
TBDR
在tbr的架构上,是不能够来一个commandbuffer就执行一个的,那是噩梦,因为任何一个commandbuffer都可能影响到到整个FrameBuffer,如果来一个画一个,那么gpu可能会在每一个drawcall上都来回搬迁所有的Tile。
TBR一般的实现策略是对于cpu过来的commandbuffer,只对他们做vetex process,然后对vs产生的结果暂时保存,等待非得刷新整个FrameBuffer的时候,才真正的随这批绘制做光栅化,做tile-based-rendering。tbr的真正的绘制管线
FrameData
FrameData这个是tbr特有的在gpu绘制时所需的存储数据,在powervr上叫做arguments buffer,在arm上叫做plolygon lists。既然tbr上是等待所有的framedata数据一起绘制pixel的,那么gpu就又多了一个优化的可能,deffered rendering,现有的大部分tbr的显卡都或多或少做了这个优化,例如ios的powervr,它多了一个叫做HSR的硬件,专门对这些framedata做处理专门对这些framedata做处理,找到这次渲染真正有可能会被写入到Framebuffer上的那些drawcall,而过滤掉大部分的drawcall。硬件巧妙的利用tbr的framedata队列实现了一种延迟渲染,即尽可能只渲染那些最终影响fb的物体,和软件层面的延迟渲染不同的是,软件层面的延迟渲染是针对一个drawcall的,对于从后到前的不透明物体绘制是每次都会绘制的,而硬件层面的延迟渲染时对一批drawcall的,它会从这批绘制里面找到最终要绘制的物体。所以现在大部分的移动端的gpu可以被称为TBDR架构