本篇为Unity官方文档的摘抄集合,为方便后续翻看。
Unity 的内置渲染管线支持不同渲染路径。渲染路径是与光照和阴影相关的一系列操作。不同的渲染路径具有不同功能和性能特征。应根据项目类型以及目标硬件,选择渲染路径。
可在 Graphics 窗口中选择项目使用的渲染路径,并可为每个摄像机覆盖该路径。
如果运行项目的设备上的 GPU 不支持所选的渲染路径,则 Unity 将自动使用较低保真度的渲染路径。例如,在无法处理延迟着色的 GPU 上,Unity 使用前向渲染。
前向渲染是内置渲染管线中的默认渲染路径。这是通用的渲染路径。
采用前向渲染方式渲染实时光源会非常消耗资源。为了抵消此成本,可以选择 Unity 在任何一个时间应该为每个像素渲染的光源数量。Unity 会以较低保真度渲染场景中的其余光源:每个顶点或每个对象。
如果项目没有使用大量实时光源,或者光照保真度对项目而言不重要,则此渲染路径可能是这个项目的不错选择。
前向渲染根据影响对象的光源在一个或多个通道中渲染每个对象。光源本身也可以通过前向渲染进行不同的处理,具体取决于它们的设置和强度。
在前向渲染中,影响每个对象的一些最亮的光源以完全逐像素光照模式渲染。然后,最多 4 个点光源采用每顶点计算方式。其他光源以球谐函数 (SH) 计算,这种计算方式会快得多,但仅得到近似值。
光源是否为每像素光源根据以下原则而定:
每个对象的渲染按如下方式进行:
例如,如果某个对象受到许多光源的影响(下图中的圆形受光源 A 到 H 的影响):
让我们假设光源 A 到 H 具有相同的颜色和强度,并且所有光源都具有自动渲染模式,因此它们将严格按照此对象的以下顺序排序。最亮的光源将以每像素光照模式渲染(A 到 D),然后最多 4 个光源以每顶点光照模式渲染(D 到 G),最后其余光源以 SH 进行渲染(G 到 H):
光源组会重叠,例如,最后一个每像素光源混合到每顶点光照模式,因此当对象和光源移动时,“光射量”(light popping) 较少。
基础通道使用一个每像素方向光和所有 SH/每顶点光源来渲染对象。此通道还会添加着色器中的所有光照贴图、环境光照和发射光照。在此通道中渲染的方向光可以具有阴影。请注意,光照贴图的对象不会从 SH 光源获得光照。
在着色器中使用“OnlyDirectional”通道标志时,前向基础通道仅渲染主方向光、环境光/光照探针和光照贴图(SH 和顶点光源不包括在通道数据中)。
对于影响此对象的每个额外的每像素光源,需要额外的渲染通道。默认情况下,这些通道中的光源没有阴影(因此在结果中,前向渲染支持一个带阴影的方向光),除非使用 multi_compile_fwdadd_fullshadows 变体快捷方式。
球谐函数光源的渲染速度_很_快。这些光源的 CPU 成本很低,并且使用 GPU 的_成本基本为零_(也就是说,基础通道始终会计算 SH 光照;但由于 SH 光源工作方式的原因,无论 SH 光源有多少,成本都完全相同)。
SH 光源的缺点:
总的来说,SH 光源通常足以达到小型动态对象的光照要求。
延迟着色是内置渲染管线中具有最大光照和阴影保真度的渲染路径。
延迟着色需要 GPU 支持,并且有一些局限性。这种着色方式不支持半透明对象(Unity 使用前向渲染来渲染这些对象)、正交投影(Unity 对这些摄像机使用前向渲染)或硬件抗锯齿(但可以使用后期处理效果来获得类似结果)。延迟着色对剔除遮罩的支持有限,并会将 Renderer.receiveShadows 标志始终视为 true。
如果项目具有大量的实时光源并需要高级别的光照保真度,而目标硬件支持延迟着色,那么此渲染路径对于该项目而言可能是一个不错的选择。
使用延迟着色时,可影响游戏对象的光源数量没有限制。所有光源都按像素进行评估,这意味着它们都能与法线贴图等正确交互。此外,所有光源都可以有剪影和阴影。
延迟着色的优点是,光照的处理开销与接受光照的像素数成正比。这取决于场景中的光量大小,而不管接受光照的游戏对象有多少。因此,可通过减少光源数量来提高性能。延迟着色还具有高度一致和可预测的行为。每个光源的效果都是按像素计算的,因此不会有在大三角形上分解的光照计算。
在缺点方面,延迟着色并不支持抗锯齿,也无法处理半透明游戏对象(这些对象使用前向渲染进行渲染)。此外,它也不支持网格渲染器 (Mesh Renderer) 的接受阴影 (Receive Shadows) 标志,并且仅在有限程度上支持剔除遮罩。最多只能使用四个剔除遮罩。也就是说,剔除层遮罩必须至少包含所有层减去四个任意层,即必须设置 32 个层中的 28 个层。否则,会产生图形瑕疵。
延迟着色要求显卡具有多渲染目标 (MRT)、着色器模型 3.0(或更高版本)并支持深度渲染纹理。从 GeForce 8xxx、Radeon X2400、Intel G45 开始,2006 年以后制造的大多数 PC 显卡都支持延迟着色。
所有至少运行 OpenGL ES 3.0 的移动设备都支持延迟着色。
注意:使用正交投影 (Orthographic projection) 时不支持延迟渲染。如果摄像机的投影模式设置为正交模式,则摄像机将回退到前向渲染。
延迟着色中的实时光源的渲染开销与接受光照的像素数成比例,并_不_依赖于场景复杂度。所以小型点光源或聚光灯的渲染成本非常低,如果它们被场景游戏对象完全或部分遮挡,那么成本甚至更低。
当然,有阴影的光源比没有阴影的光源的成本高得多。在延迟着色中,对于每个阴影投射光源,仍然需要将投射阴影的游戏对象渲染一次或多次。此外,应用阴影的光照着色器的渲染开销高于禁用阴影时的渲染开销。
如果对象的着色器不支持延迟着色,则会在延迟着色结束后使用前向渲染路径来渲染这些对象。
下面列出了 G 缓冲区中渲染目标 (RT0 - RT4) 的默认布局。数据类型放置在每个渲染目标的各个通道中。使用的通道显示在括号内。
因此,默认的 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 缓冲区纹理设置为全局着色器属性供着色器以后访问(_CameraGBufferTexture0 .._CameraGBufferTexture3 指定)。
光照通道根据 G 缓冲区和深度来计算光照。光照是在屏幕空间内计算的,因此处理所需的时间与场景复杂性无关。光照将添加到发射缓冲区。
不与摄像机近平面相交的点光源和聚光灯将渲染为 3D 形状,并会启用 Z 缓冲区对场景的测试。因此,部分或完全遮挡的点光源和聚光灯的渲染成本很低。方向光以及与近平面相交的点光源/聚光灯将渲染为全屏四边形。
如果光源启用了阴影,那么也会在此通道中渲染并应用阴影。请注意,阴影并非是“无成本”的;需要渲染阴影投射物,并且必须应用更复杂的光照着色器。
唯一可用的光照模型是标准 (Standard) 光照模型。如果需要不同的模型,可修改光照通道着色器,方法是将内置着色器中的 Internal-DeferredShading.shader 文件的修改版本放入“Assets”文件夹中名为“Resources”的文件夹内。然后打开 Graphics 设置(菜单:Edit > Project Settings,然后单击 Graphics 类别)。将“Deferred”下拉选单改为“Custom Shader”。然后,更改当前使用的着色器对应的着色器 (Shader) 选项。
旧版延迟(光照预通道)类似于延迟着色,只是采用不同的技术并进行不同的折中。它不支持 Unity 5 基于物理的标准着色器。
从 Unity 5.0 开始,旧版延迟渲染路径被认为是旧版功能,因为它不支持某些渲染功能(例如标准着色器、反射探针)。新项目应考虑改用延迟着色渲染路径。使用正交投影 (Orthographic projection) 时不支持延迟渲染。如果摄像机的投影模式设置为正交模式,则摄像机将始终使用前向渲染。
使用延迟光照时,可影响对象的光源数量没有限制。所有光源都按像素进行评估,这意味着它们都能与法线贴图等正确交互。此外,所有光源都可以有剪影和阴影。
延迟光照的优点是,光照的处理开销与接受光照的像素数成正比。这取决于场景中的光量大小,而不管接受光照的对象有多少。因此,可通过减少光源数量来提高性能。延迟光照还具有高度一致和可预测的行为。每个光源的效果都是按像素计算的,因此不会有在大三角形上分解的光照计算。
在缺点方面,延迟光照并不支持抗锯齿,也无法处理半透明对象(这些对象将使用前向渲染进行渲染)。此外,它也不支持网格渲染器 (Mesh Renderer) 的接受阴影 (Receive Shadows) 标志,并且仅在有限程度上支持剔除遮罩。最多只能使用四个剔除遮罩。也就是说,剔除层遮罩必须至少包含所有层减去四个任意层,即必须设置 32 个层中的 28 个层。否则,将产生图形瑕疵。
延迟光照要求显卡具有着色器模型 3.0(或更高版本)、支持深度渲染纹理以及具有双面模板缓冲区。 2004 年以后制造的大多数 PC 显卡都支持延迟光照,包括 GeForce FX 及更高版本、Radeon X1300 及更高版本、 Intel 965/GMA X3100 及更高版本。在移动端,所有支持 OpenGL ES 3.0 的 GPU 都支持延迟光照,而一部分 支持 OpenGL ES 2.0 的 GPU 也支持延迟光照(即支持深度纹理的 GPU)。
延迟光照中的实时光源的渲染开销与接受光照的像素数成比例,并_不_依赖于场景复杂度。所以小型点光源或聚光灯的渲染成本非常低,如果它们被场景对象完全或部分遮挡,那么成本甚至更低。
当然,有阴影的光源比没有阴影的光源的成本高得多。在延迟光照中,对于每个阴影投射光源,仍然需要将投射阴影的对象渲染一次或多次。此外,应用阴影的光照着色器的渲染开销高于禁用阴影时的渲染开销。
使用延迟光照时,Unity 中的渲染过程在三个通道中进行:
(1)基础通道:渲染对象以生成具有深度、法线和镜面反射能力的屏幕空间缓冲区。
(2)光照通道:将先前生成的缓冲区用于计算光照以进入另一个屏幕空间缓冲区。
(3)最终通道:再次渲染对象。它们会获取计算出的光照,将其与颜色纹理相结合,并添加环境/发射光照。
如果对象的着色器无法处理延迟光照,则会在此过程结束后使用前向渲染路径来渲染这些对象。
基础通道将每个对象渲染一次。视图空间法线和镜面反射能力将渲染到单个 ARGB32 渲染纹理中(法线位于 RGB 通道中,而镜面反射强度位于 A 通道中)。如果平台和硬件允许将 Z 缓冲区作为纹理读取,则不会显式渲染深度。如果无法将 Z 缓冲区作为纹理访问,则会使用着色器替换在另外的渲染通道中渲染深度。
基础通道的结果是填充了场景内容的 Z 缓冲区以及包含法线和镜面反射能力的渲染纹理。
光照通道根据深度、法线和镜面反射能力来计算光照。光照是在屏幕空间内计算的,因此处理所需的时间与场景复杂性无关。光照缓冲区是单个 ARGB32 渲染纹理,其中在 RGB 通道中包含漫射光照,而在 A 通道中包含单色镜面光照。光照值采用对数编码,因此提供的动态范围高于 ARGB32 纹理通常可能提供的范围。如果摄像机启用了 HDR 渲染,则光照缓冲区为 ARGBHalf 格式,并且不执行对数编码。
不与摄像机近平面相交的点光源和聚光灯将渲染为 3D 形状(的正面),并会启用对场景的深度测试。与近平面相交的光源也用 3D 形状进行渲染,但作为背面并进行反向深度测试。因此,部分或完全遮挡的光源的渲染成本很低。如果光源同时与摄像机的远平面和近平面相交,则不能使用上述优化,而光源会被绘制为紧密四边形并且不进行深度测试。
以上说明不适用于方向光;方向光总是渲染为全屏四边形。
如果光源启用了阴影,那么也会在此通道中渲染并应用阴影。请注意,阴影并非是“无成本”的;需要渲染阴影投射物,并且必须应用更复杂的光照着色器。
唯一可用的光照模型是 Blinn-Phong。如果需要不同的模型,可修改光照通道着色器,方法是将内置着色器中的 Internal-PrePassLighting.shader 文件的修改版本放入“Assets”文件夹中名为“Resources”的文件夹内。然后,选择 Edit > Project Settings > Graphics 窗口。将“Legacy Deferred”下拉选单改为“Custom Shader”。然后,更改当前使用的光照着色器对应的着色器 (Shader) 选项。
最终通道将产生最终渲染的图像。在此阶段将再次使用着色器渲染所有对象,这些着色器会获取光照,将其与纹理相结合,并添加发射光照。在最终通道中还会应用光照贴图。在靠近摄像机的位置将使用实时光照,并且仅添加烘焙间接光照。因此会交叉淡入远离摄像机的完全烘焙光照。
旧版顶点光照 (Legacy Vertex Lit) 是具有最低光照保真度且不支持实时阴影的渲染路径。这是前向渲染路径的子集。
顶点光照路径通常在一个通道中渲染每个对象,并为每个顶点计算所有光源的光照。
顶点光照路径是最快的渲染路径,具有最广泛的硬件支持。
由于所有光照都是在顶点级别计算的,因此该渲染路径不支持大多数每像素效果:阴影、法线贴图、光照剪影和高度细节化的镜面高光都不受支持。
延迟 | 前向 | 旧版延迟 | 顶点光照 | |
---|---|---|---|---|
功能 | ||||
每像素光照(法线贴图、光照剪影) | 是 | 是 | 是 | - |
实时阴影 | 是 | 带有警告 | 是 | - |
反射探针 | 是 | 是 | - | - |
深度和法线缓冲区 | 是 | 其他渲染pass | 是 | - |
软粒子 | 是 | - | 是 | - |
半透明对象 | - | 是 | - | 是 |
抗锯齿 | - | 是 | - | 是 |
光照剔除遮罩 | 受限 | 是 | 受限 | 是 |
光照保真度 | 全部每像素 | 部分每像素 | 全部每像素 | 全部每顶点 |
性能 | ||||
每像素光照的成本 | 照射像素数量 | 像素数量 * 照射对象数量 | 照射像素数量 | - |
正常渲染对象的次数 | 1 | 每像素光照的数量 | 2 | 1 |
简单场景的开销 | 高 | 无 | 中 | 无 |
平台支持 | ||||
PC (Windows/Mac) | Shader Model 3.0+ 和 MRT | 所有 | Shader Model 3.0+ | 所有 |
移动端 (iOS/Android) | OpenGL ES 3.0 和 MRT、Metal(在搭载 A8 或更高版本 SoC 的设备上) | 所有 | OpenGL ES 2.0 | 所有 |
游戏主机 | XB1、PS4 | 所有 | XB1、PS4、360 | - |
包含有关在内置渲染管线中使用 CommandBuffer 的信息。有关在渲染管线中基于可编程渲染管线使用 CommandBuffer 的信息,请参阅在可编程渲染管线中调度和执行渲染命令。
CommandBuffer 保存渲染命令列表(例如设置渲染目标或绘制给定网格)。可以指示 Unity 在内置渲染管线中的各个点安排和执行这些命令,因此,您可以自定义和扩展 Unity 的渲染功能。
可以使用 Graphics.ExecuteCommandBuffer API 立即执行 CommandBuffer,也可以进行安排,让它们在渲染管线中的给定点执行。要安排它们,请使用 Camera.AddCommandBuffer API 与CameraEvent 枚举,以及 Light.AddCommandBuffer API 与 LightEvent 枚举。要查看 Unity 何时执行以这种方式安排的 CommandBuffer,请参阅 CameraEvent 和 LightEvent 的执行顺序。
有关可以使用 CommandBuffer 执行的命令的完整列表,请参阅 CommandBuffer API 文档。请注意,一些命令仅在某些硬件上受支持。例如,与光线追踪有关的命令仅在 DX12 中受支持。
Unity 博客文章扩展 Unity 5 渲染管线:CommandBuffer 介绍了内置渲染管线中的 CommandBuffer,并包含示例项目和示例代码。它介绍如何使用 CommandBuffer 来实现几种不同的效果,并包含一个示例项目和示例代码。项目是为 Unity 的旧版本创建的,但原理相同。
CameraEvents 执行顺序取决于项目使用的渲染路径。
在上面的“渲染阴影”阶段,对于每个投射阴影的光源,Unity 执行以下步骤:
Win/Mac/Linux | iOS/Android | 游戏主机 | ||
延迟光照 | SM3.0、GPU 支持 | - | 是 | |
前向渲染 | 是 | 是 | 是 | |
顶点光照渲染 | 是 | 是 | - | |
实时阴影 | GPU 支持 | GPU 支持 | 是 | |
图像效果 | 是 | 是 | 是 | |
可编程着色器 | 是 | 是 | 是 | |
固定函数着色器 | 是 | 是 | - |
实时阴影 (Realtime Shadows) 适用于大多数 PC、游戏主机和移动平台。在 Windows (Direct3D) 上,GPU 还需要支持阴影贴图功能;自 2003 年以后,大多数独立 GPU 都支持这些功能,而自 2007 年以后,大多数集成 GPU 也支持这些功能。从技术上讲,在 Direct3D 9 上,GPU 必须支持 D16/D24X8 或 DF16/DF24 纹理格式;在 OpenGL 上,必须支持 GL_ARB_depth_texture 扩展。
移动端阴影 (iOS/Android) 要求具备 OpenGL ES 2.0 和 GL_OES_depth_texture 扩展或者 OpenGL ES 3.0。最需要注意的是,该扩展在基于 Tegra 3 和 Tegra 4 的 Android 设备上不存在,因此阴影在这些设备上不起作用。
后期处理效果要求有渲染到纹理功能;此功能通常在本世纪以来制造的硬件产品上都是受支持的。
可以编写可编程着色器或固定函数着色器。可编程着色器在所有平台上都受支持,默认为 Shader Model 2.0(桌面端)和 OpenGL ES 2.0(移动端)。如果想要更多功能,可定位更高版本的着色器模型。固定函数着色器在除游戏主机外的所有平台上都受支持。