目录
1.关于渲染管线
在 Unity 中,可以选择不同的渲染管线。渲染管线执行一系列操作来获取场景的内容,并将这些内容显示在屏幕上。概括来说,这些操作如下:
- Culling(剔除)
- Rendering(渲染)
- Post-processing(后期处理)
不同的渲染管线具有不同的功能和性能特征,并且适用于不同的游戏、应用程序和平台。
将项目从一个渲染管线切换到另一个渲染管线可能很困难,因为不同的渲染管线使用不同的着色器输出,并且可能没有相同的特性。因此,必须要了解 Unity 提供的不同渲染管线,以便可以在开发早期为项目做出正确决定。
Unity 提供以下渲染管线:
- 内置渲染管线是 Unity 的默认渲染管线,其自定义有限。
- 通用渲染管线 (URP)是一种可快速轻松自定义的可编程渲染管线,允许您在各种平台上创建优化的图形。
- 高清渲染管线 (HDRP)是一种可编程渲染管线,可让您在高端平台上创建出色的高保真图形。
- 可以使用 Unity 的可编程渲染管线 API 来创建自定义的可编程渲染管线 (SRP)。这个过程可以从头开始,也可以修改 URP 或 HDRP 来适应具体需求。
2.内置渲染管线
Unity的内置渲染管线是通用的渲染管线。·
内置渲染管线在自定义扩展方面比可编程渲染管线受到的限制更多,但是您可以在不同的渲染路径之间进行选择,并通过命令缓冲区和回调来扩展其功能。
A.内置渲染管线中的渲染路径
Unity的内置渲染管线支持不同渲染路径。渲染路径是与光照和阴影相关的一系列操作。不同的渲染路径具有不同功能和性能特征。应根据项目类型以及目标硬件,确定哪种渲染路径最适合您的项目。
可在Graphics窗口中选择项目使用的渲染路径,也可以为每个摄像机覆盖该路径。
如果运行项目的设备上的GPU不支持所选的渲染路径,则Unity将自动使用较低保真度的渲染路径。例如,在无法处理延迟着色的GPU上,Unity使用前向渲染。
> 前向渲染(Forward)
前向渲染是内置渲染管线中的默认渲染路径。这是通用的渲染路径。
采用前向渲染方式渲染实时光源会非常消耗资源。为了抵消此成本,可以选择逐像素渲染的光源数量。Unity会以较低保真度渲染场景中的其余光源:逐顶点或逐对象。
如果项目没有使用大量实时光源,或者光照保真度对项目而言不重要,则此渲染路径可能是这个项目的不错选择。
> 延迟着色(Deferred)
延迟着色是内置渲染管线中具有最大光照和阴影保真度的渲染路径。
延迟着色需要GPU支持,并且有一些局限性。这种着色方式不支持半透明对象(Unity使用前向渲染来渲染这些对象)、正交投影(Unity对这些摄像机使用前向渲染)或硬件抗锯齿(但可以使用后期处理效果来获得类似效果)。延迟着色对剔除遮罩的支持有限,并会将Renderer.receiveShadows标志始终视为true。
如果项目具有大量的实时光源并需要高级别的光照保真度,而目标硬件支持延迟着色,那么此渲染路径对于该项目而言可能是一个不错的选择。
> 旧版延迟着色 (Legacy Deferred)
旧版延迟着色(光照预通道)类似于延迟着色,只是采用不同的技术并进行不同的折中。它不支持Unity 5基于物理的标准着色器。
> 旧版顶点光照(Legacy Vertex Lit)
旧版顶点光照 (Legacy Vertex Lit) 是具有最低光照保真度且不支持实时阴影的渲染路径。这是前向渲染路径的子集。
> 渲染路径比较
延迟着色 | 前向渲染 | 旧版延迟着色 | 旧版顶点光照 | |
---|---|---|---|---|
功能 | ||||
逐像素光照(法线贴图、光照剪影) | 是 | 是 | 是 | - |
实时阴影 | 是 | 带有警告 | 是 | - |
反射探针 | 是 | 是 | - | - |
深度和法线缓冲区 | 是 | 附加渲染通道 | 是 | |
软粒子 | 是 | - | 是 | - |
半透明对象 | - | 是 | - | 是 |
抗锯齿 | - | 是 | - | 是 |
光照剔除遮罩 | 受限 | 是 | 受限 | 是 |
光照保真度 | 全部逐像素 | 部分逐像素 | 全部逐像素 | 全部逐顶点 |
性能 | ||||
逐像素光照的成本 | 照射像素数量 | 像素数量 * 照射对象数量 | 照射像素数量 | - |
正常渲染对象的次数 | 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 | - |
前向渲染路径(Forward)
前向渲染路径根据影响对象的光源在一个或多个通道中渲染每个对象。光源本身也可以通过前向渲染进行不同的处理,具体取决于它们的设置和强度。
1.实现详情
在前向渲染中,影响每个对象的最亮的光源以逐像素光照模式渲染。然后,最多 4 个点光源采用逐顶点计算方式。其他光源以球谐函数 (SH) 计算,这种计算方式会快得多,但仅得到近似值。光源是否为逐像素光源根据以下原则而定:
> Render Mode 设置为 Not Important 的光源始终为逐顶点光源或SH光源。
> 最亮的方向光始终为逐像素光源。
> Render Mode 设置为 Important 的光源始终为逐像素光源。
> 如果上述情况导致光源数少于当前的 Pixel Light Count,则按照亮度降低的顺序,更多光源采用逐像素渲染方式。
如下方式渲染对象:
> 基础通道应用一个逐像素方向光和所有逐顶点/SH 光源。
> 其他逐像素光源在额外的通道中渲染(每个光源对应一个通道)。
例如,如果某个对象受到许多光源的影响(下图中的圆形受光源 A 到 H 的影响):
让我们假设光源 A 到 H 具有相同的颜色和强度,并且所有光源的Render Mode均为Auto,因此它们将严格按照此对象的以下顺序排序。最亮的光源将以逐像素光照模式渲染(A 到 D),然后最多 4 个光源以逐顶点光照模式渲染(D 到 G),最后其余光源以 SH 进行渲染(G 到 H):
注意:光源组会重叠,例如,最后一个逐像素光源混合到逐顶点光照模式,因此当对象和光源移动时,“光射量”(light popping) 较少。
2.基础通道(Base Pass)
基础通道使用一个逐像素方向光和所有 SH/逐顶点光源来渲染对象。此通道还会添加着色器中的所有光照贴图、环境光和自发光。在此通道中渲染的方向光可以具有阴影。请注意,光照贴图的对象不会从 SH 光源获得光照。
请注意,在着色器中使用“OnlyDirectional”通道标志时,前向基础通道仅渲染主方向光、环境光/光照探针和光照贴图(SH 和顶点光源不包括在通道数据中)。
3.附加通道(Additional Pass)
对于影响此对象的每个额外的逐像素光源,需要额外的渲染通道。默认情况下,这些通道中的光源没有阴影(因此在结果中,前向渲染支持一个带阴影的方向光),除非使用 multi_compile_fwdadd_fullshadows。
4.性能注意事项
球谐函数光源的渲染速度很快。这些光源的 CPU 成本很低,并且使用 GPU 的成本基本为零(也就是说,基础通道始终会计算 SH 光照;但由于 SH 光源工作方式的原因,无论 SH 光源有多少,成本都完全相同)。
SH 光源的缺点:
> 按对象的顶点而不是按像素计算。这意味着它们不支持光照Cookies和法线贴图。
> SH 光照的频率很低。SH 光源无法实现快速的光照过渡。它们也只影响漫反射光照(频率对镜面高光而言太低)。
> SH 光照不是局部光照;SH 点光源或聚光灯在靠近某种表面时“看起是错误的”。
总的来说,SH 光源通常足以达到小型动态对象的光照要求。
延迟着色渲染路径(Deferred)
1.概述
使用延迟着色时,影响游戏对象的光源数量没有限制。所有光源都按像素进行评估,这意味着它们都能与法线贴图等正确交互。此外,所有光源都可以有剪影和阴影。
延迟着色的优点是,光照的处理开销与接受光照的像素数成正比。这取决于场景中的光源数量,而不管接受光照的游戏对象有多少。因此,可通过减少光源数量来提高性能。延迟着色还具有高度一致和可预测的行为。每个光源的效果都是按像素计算的,因此不会有在大三角形上分解的光照计算。
在缺点方面,延迟着色并不支持抗锯齿,也无法处理半透明游戏对象(这些对象使用前向渲染进行渲染)。此外,它也不支持网格渲染器 (Mesh Renderer) 的接受阴影 (Receive Shadows) 标志,并且仅在有限程度上支持剔除遮罩。最多只能使用四个剔除遮罩。也就是说,剔除层遮罩必须至少包含所有层减去四个任意层,即必须设置 32 个层中的 28 个层。否则,会产生图形瑕疵。
2.要求
延迟着色要求显卡具有多渲染目标 (MRT)、着色器模型 3.0(或更高版本)并支持深度渲染纹理。从 GeForce 8xxx、Radeon X2400、Intel G45 开始,2006 年以后制造的大多数 PC 显卡都支持延迟着色。
所有至少运行 OpenGL ES 3.0 的移动设备都支持延迟着色。
注意:使用正交投影 (Orthographic projection) 时不支持延迟渲染。如果摄像机的投影模式设置为正交模式,则摄像机将回退到前向渲染。
3.性能注意事项
延迟着色中的实时光源的渲染开销与接受光照的像素数成比例,并不依赖于场景复杂度。所以小型点光源或聚光灯的渲染成本非常低,如果它们被场景游戏对象完全或部分遮挡,那么成本甚至更低。
当然,有阴影的光源比没有阴影的光源的成本高得多。在延迟着色中,对于每个阴影投射光源,仍然需要将投射阴影的游戏对象渲染一次或多次。此外,应用阴影的光照着色器的渲染开销高于禁用阴影时的渲染开销。
4.实现详情
如果对象的着色器不支持延迟着色,则会在延迟着色结束后使用前向渲染路径来渲染这些对象。
下面列出了几何缓冲区(G 缓冲区)中渲染目标 (RT0 - RT4) 的默认布局。数据类型放置在每个渲染目标的各个通道中。使用的通道显示在括号内。
> RT0,ARGB32 格式:漫射颜色 (RGB),遮挡 (A)。
> RT1,ARGB32 格式:镜面反射颜色 (RGB),粗糙度 (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。
5.G缓冲区通道
G 缓冲区通道将每个游戏对象渲染一次。漫射和镜面反射颜色、表面平滑度、世界空间法线和发射+环境+反射+光照贴图都将渲染到 G 缓冲区纹理中。G 缓冲区纹理设置为全局着色器属性供着色器以后访问 (CameraGBufferTexture0 ..CameraGBufferTexture3 names)。
6.光照通道
光照通道根据 G 缓冲区和深度来计算光照。光照是在屏幕空间内计算的,因此处理所需的时间与场景复杂性无关。光照将添加到发射缓冲区。
不与摄像机近平面相交的点光源和聚光灯将渲染为 3D 形状,并会启用 Z 缓冲区对场景的测试。因此,部分或完全遮挡的点光源和聚光灯的渲染成本很低。方向光以及与近平面相交的点光源/聚光灯将渲染为全屏四边形。
如果光源启用了阴影,那么也会在此通道中渲染并应用阴影。请注意,阴影并非是“无成本”的;需要渲染阴影投射物,并且必须应用更复杂的光照着色器。
唯一可用的光照模型是标准 (Standard) 光照模型。如果需要不同的模型,可修改光照通道着色器,方法是将内置着色器中的 Internal-DeferredShading.shader 文件的修改版本放入Assets文件夹中名为“Resources”的文件夹内。然后打开 Graphics 设置(菜单:Edit > Project Settings,然后单击 Graphics 类别)。将Deferred下拉选单改为Custom Shader。然后,更改当前使用的着色器对应的着色器 (Shader) 选项。
旧版延迟着色渲染路径(Legacy Deferred)
旧版顶点光照渲染路径(Legacy Vertex Lit)
B.使用命令缓冲区来扩展内置渲染管线
命令缓冲区可保存一组渲染命令。您可以指示 Unity 调用和执行这些命令。
本部分包含有关在内置渲染管线中使用命令缓冲区的信息。有关在可编程渲染管线中使用命令缓冲区的信息,请参阅在可编程渲染管线中调度和执行渲染命令。
有关可以使用命令缓冲区执行的命令的完整列表,请参阅 CommandBuffer API 文档。请注意,一些命令仅在某些硬件上受支持。例如,与射线追踪有关的命令仅在 DX12 中受支持。
立即执行命令缓冲区
可以使用 Graphics.ExecuteCommandBuffer API 立即执行命令缓冲区。
调用命令缓冲区
在内置渲染管线中,可以在渲染循环中的特定时间执行命令缓冲区。为此,请将 Camera.AddCommandBuffer API 与 CameraEvent 枚举一起使用,并将 Light.AddCommandBuffer API 与 LightEvent 枚举一起使用。
例如,可以将命令缓冲区与 AfterGBuffer CameraEvent 结合使用,从而将其他游戏对象渲染到延迟管线中(在管线处理所有不透明的游戏对象之后)。
CameraEvent 执行顺序
延迟渲染路径 |
---|
BeforeGBuffer |
Unity 渲染不透明几何体 |
AfterGBuffer |
Unity 解析深度 |
BeforeReflections |
Unity 渲染默认反射 |
Unity 渲染反射探针反射 |
AfterReflections |
Unity 将反射复制到 G 缓冲区的 Emissive 通道 |
BeforeLighting |
Unity 渲染阴影(请参阅LightEvent 执行顺序) |
AfterLighting |
BeforeFinalPass |
Unity 对FinalPass进行处理。 |
AfterFinalPass |
BeforeForwardOpaque(仅当存在无法以延迟方式渲染的不透明几何体时调用) |
Unity 渲染无法以延迟方式渲染的不透明几何体 |
AfterForwardOpaque(仅当存在无法以延迟方式渲染的不透明几何体时调用) |
BeforeSkybox |
Unity 渲染天空盒 |
AfterSkybox |
Unity 渲染光环 |
BeforeImageEffectsOpaque |
如果使用 Post-processing Stack V2 包,则 Unity 会应用仅限不透明的后期处理效果 |
AfterImageEffectsOpaque |
BeforeForwardAlpha |
Unity 会渲染透明几何体以及具有 Screen Space - Camera 渲染模式的UI画布 |
AfterForwardAlpha |
BeforeHaloAndLensFlares |
Unity 渲染镜头光晕 |
AfterHaloAndLensFlares |
BeforeImageEffects |
如果使用 Post-processing Stack V2 包,则 Unity 会应用后期处理效果 |
AfterImageEffects |
AfterEverything |
Unity 对渲染模式不是 Screen Space - Camera 的 UI 画布进行渲染 |
前向渲染路径 |
---|
BeforeDepthTexture |
Unity 渲染不透明几何体的深度 |
AfterDepthTexture |
BeforeDepthNormalsTexture |
Unity 渲染不透明几何体的深度法线 |
AfterDepthNormalsTexture |
Unity 渲染阴影(请参阅LightEvent 执行顺序) |
BeforeForwardOpaque |
Unity 渲染不透明几何体 |
AfterForwardOpaque |
BeforeSkybox |
Unity 渲染天空盒 |
AfterSkybox |
Unity 渲染光环 |
BeforeImageEffectsOpaque |
如果使用 Post-processing Stack V2 包,则 Unity 会应用仅限不透明的后期处理效果 |
AfterImageEffectsOpaque |
BeforeForwardAlpha |
Unity 会渲染透明几何体以及具有 Screen Space - Camera 渲染模式的UI画布 |
AfterForwardAlpha |
BeforeHaloAndLensFlares |
Unity 渲染镜头光晕 |
AfterHaloAndLensFlares |
BeforeImageEffects |
如果使用 Post-processing Stack V2 包,则 Unity 会应用后期处理效果 |
AfterImageEffects |
AfterEverything |
Unity 对渲染模式为 Screen Space - Camera 的 UI 画布进行渲染 |
LightEvent 执行顺序
在上面的“渲染阴影”阶段,对于每个投射阴影的光源,Unity 执行以下步骤:
BeforeShadowMap | |
Unity 渲染当前通道的所有阴影投射物 | 对每个通道进行重复 |
AfterShadowMap | |
BeforeScreenSpaceMask | |
Unity 将阴影贴图收集到屏幕空间缓冲区中并执行过滤 | |
AfterScreenSpaceMask |
其他资源
Unity 博客文章扩展 Unity 5 渲染管线:命令缓冲区 (Extending Unity 5 rendering pipeline: Command Buffers) 介绍了内置渲染管线中的命令缓冲区,并包含示例项目和示例代码。这篇文章与 Unity 的旧版本有关,但原理相同。