Universal Render Pipeline
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
1 URP的常见问题回答
- URP和HDRP(High Definition Render Pipeline)不能混用。
- 可以从内建render pipeline转到URP。可以用升级器(upgrade)升级内建shader到URP shader。如果自定义的shader的话,需要手动去upgrade。
- 不能在运行期换pipeline asset。
- URP和HDRP之间不能换用。
- 通过Package Manager获取URP的package
- 在URP Asset的【Player Setting】界面上可以找到Dynamic Batching的checkbox
- 选中材质球时,在Inspector面板中,找到Render Face选项,选择Both选项,即可开启Double Sided Global Illumination。
- URP适用于各种平台,包括PC和mobile
- 在Built-in RP和URP功能对照表中,标识为
Not Supported
的功能,表示没有且不会在后续版本中实现。 - 如果在build URP工程时很慢,检查以下shader stripping是否设置对,要strip掉可以strip掉的shader。
- 缺省地,URP是在linear space中工作,可以在Player Setting中将其设置为在gamma space中工作。
- 通过创建ScriptableRendererFeature脚本,使用scriptable render pass可以扩展URP的功能。
2 URP Asset
URP版本:8.2.0 源网页
要使用URP asset,需要创建一个URP asset,并在【Graphic settings】界面将其赋值使用。URP asset控制图形渲染的功能,设置图形渲染的质量等级。URP asset本身是一个scriptable object。它继承自RenderPipelineAsset
类。在一个工程中可以使用多个URP asset,并且可以在它们之间切换使用,比如有个URP asset是启用了阴影,另一个URP asset关闭了阴影。
URP有以下几大类的控制选项,如下:
- General
- Quality
- Lighting
- Shadows
- Post-processing
- Advanced
下面的图显示了这几个控制选项的UI:
2.1 General
这是一些用于控制管道渲染框架的核心部分常规设置
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
Depth Texture | 当在一个摄像机对象的inspector界面上启用此项时,URP将会在shader中创建一个深度纹理_CameraDepthTexture 。缺省地URP将把这个深度纹理交给你场景中的所有的摄像机去使用之。 |
m_RequireDepthTextureProp |
Opaque Texture | 当在一个摄像机对象的inspector界面上启用此项时,URP将会在shader中创建一个不透明的深度纹理_CameraOpaqueTexture 。缺省地,URP将这个深度纹理交给你场景中的所有的摄像机使用。这个深度纹理起的作用,就很类似于built-in render pipeline中的GrabPass。在URP渲染任意的透明状网格(transparent mesh)时,该纹理将会提供一个当前场景的一个快照(snapshot) |
m_RequireOpaqueTextureProp |
Opaque Downsampling | 设置Opaque Texture属性的降采样方式,有None(不采样)、2倍线性过滤(2x Bilinear),、4倍线性过滤(4x Bilinear),、4倍盒状过滤(4x Bilinear),其中4倍盒状过滤产生一种轻柔羽化的效果 | m_OpaqueDownsamplingProp |
Terrain Holes | 禁用此项的话,在build包的时候,URP将会移出所有的Terrain hole shader变体,将会减少build包的时间 | – |
2.2 Quality
Qulity项相关管的属性控制URP的渲染质量级别。通过控制这些属性,可以在低端硬件上提高性能,在高端硬件上提高图形质量。如果要为不同的硬件设置不同的设置,则可以在多个Universal Render Pipeline资源中配置这些设置,然后根据需要在这些设置中切换。
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
HDR | 启用此选项后,默认情况下,场景中的每个摄像机都可以在HDR中进行渲染。如果定位的是低端硬件,则可以禁用此选项以跳过HDR计算并获得更好的性能。当在一个摄像机对象的inspector界面上,为这个摄像机对象关闭使用HDR。 | m_HDR |
MSAA | 当开启此项,在渲染时,默认情况下对场景中的每个摄像机都使用多重采样反走样(Multi Sample Anti-aliasing)。这样可以使几何图形的边缘变柔和,因此不会出现锯齿或闪烁。在下拉菜单中,选择每个像素要使用多少个样本:2x,4x或8x。选择的样本越多,对象边缘越平滑。如果您想跳过MSAA计算,或者在2D游戏中不需要它们,请选择Disable。当在一个摄像机对象的inspector界面上,为这个摄像机对象关闭使用MSAA。 | m_MSAA |
Render Scale | 此滑块缩放渲染目标分辨率(render target resolution)(而不是当前设备的分辨率)。如果出于性能原因要以较小的分辨率进行渲染,或者要放大渲染以提高质量,请使用此选项。这只会缩放游戏渲染。UI呈现保留为设备的原始分辨率。 | m_RenderScale |
2.3 Lighting
Lighting相关的属性这些设置会影响场景中的灯光。如果禁用其中一些设置,将会从Shader代码中删除相关的keyword。如果您确定某些keyword肯定不会在程序中使用上,则可以将其禁用以提高性能并减少构建时间。
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
Main Light | 这些设置会影响场景中的directional light。 您可以通过在Lighting的Inspector面板中将其分配为Sun Source来选择它。 如果您不指定太阳源,则URP会将场景中最亮的directional light光视为主光。您可以在Pixel Lighting和None这两个选项中进行选择。 如果您选择None,则即使您设置了光源,URP也不会用主光源参与渲染计算 | m_MainLightRenderingModeProp |
Cast Shadows | 当勾选此项时,Main Light将会在场景产生影子 | m_MainLightShadowsSupportedProp |
Shadow Resolution | 这可以控制主光源的阴影贴图纹理的大小。高分辨率可提供更清晰,更详细的阴影。 如果内存或渲染时间有问题,请尝试使用较低的分辨率。 | m_MainLightShadowmapResolutionProp |
Additional Lights | 在这里,您可以选择使用其他光源来补充您的main light。在Per Vertex,Per Pixel或Disabled之间进行选择 | m_AdditionalLightsRenderingModeProp |
Per Object Limit | 每一个game object中,可以被多少个additional light所照亮。此滑块用来设置这个个数 | m_AdditionalLightsPerObjectLimitProp |
Cast Shadows | 勾选此选项,可以控制additional lights是否能在场景中投下阴影。 | m_AdditionalLightShadowsSupportedProp |
Shadow Resolution | 附加光投射有向阴影的所使用的阴影贴图纹理的大小。这是一个纹理集,最多可容纳16个阴影贴图。高分辨率可提供更清晰,更详细的阴影。 如果内存或渲染时间有问题,请尝试使用较低的分辨率。 | m_AdditionalLightShadowmapResolutionProp |
2.4 Shadows
这些设置会影响阴影的外观和行为。它们还会影响性能,因此您可以在此处进行调整,以在视觉质量和阴影渲染速度之间取得最佳平衡。
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
Distance | 这个属性将指定一个值,当某个game object离摄像机的距离大于此值时,URP将不会渲染这个object的阴影 | m_ShadowDistanceProp |
Cascades | 选择阴影的 层叠(cascade) 数。大量的层叠为您提供了更接近相机的阴影。选项包括:None,Two,Four如果您遇到性能问题,请尝试减少级联数量。还可以在设置下方的部分中配置阴影的距离。距离相机越远,阴影变得越不细腻。 | m_ShadowCascadesProp m_ShadowCascade2SplitProp m_ShadowCascade4SplitProp |
Soft Shadows | 如果为main light或additional light启用了阴影,则可以启用这个Soft Shadows选项,以在阴影贴图上添加更平滑的过滤效果。这样可以使阴影上的边缘平滑。如果禁用此功能,则渲染速度会更快,但阴影边缘会更锐利(可能会像素化)。 | m_SoftShadowsSupportedProp |
2.5 Post-processing
本部分允许您 微调(fine-tune) 全局后处理设置。
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
Grading Mode | 选择用于项目的颜色分级(color grading,通常是指对最终的画面进行颜色和亮度的改变或矫正)的模式。分为两种:•高动态范围(HDR):类似于电影制作工作流程,此模式最适用于高精度分级。 Unity在色调映射(tone mapping)之前应用颜色分级。•低动态范围:此模式遵循更经典的工作流程。 在色调映射之后,Unity会应用有限范围的颜色分级。 | m_ColorGradingMode |
LUT Size | URP会使用 查找纹理(look-up texture,LUT) 来进行color grading。查找纹理可分为 内部(internal) 和 外部(external) 本属性项就是用来指定LUT的的大小。 较大的大小值可提供更高的精度,但可能会降低性能。增加内存的使用。在开始color grading之前就需要确定好尺寸。本选项的默认值为32,这是一个能在速度和质量之间的取得良好平衡的值。 | m_ColorGradingLutSize |
2.6 Advanced
本部分允许您微调较少更改的设置,这些设置会影响更深的渲染功能和Shader组合。
属性名 | 描述 | 对应的编辑器变量名称 |
---|---|---|
SRP Batcher | 选中此框以启用SRP Batcher。如果您有许多使用不同的材质球,但是它们使用了相同的着色器,这将很有用。SRP Batcher是一个内部循环(inner loop),可在不影响GPU性能的情况下加快CPU渲染速度。使用SRP Batcher时,它将在内部循环中替换SRP的渲染相关的代码。 | m_SRPBatcher |
Dynamic Batching | 启用动态批处理,以使render pipeline自动批处理共享同一材质的小型动态对象。 这对于不支持GPU instancing的平台和图形API很有用。如果目标硬件确实支持GPU instancing,请禁用动态批处理。您可以在运行时更改此设置。 | m_SupportsDynamicBatching |
Mixed Lighting | 启用混合灯光(Mixed Lighting),启用本选项时,会告诉pipeline在创建游戏时,包含上mixed lighting相关的shader variants。 | m_MixedLightingSupportedProp |
Debug Level | 设置render pipeline生成的调试信息的等级,分为以下几种: Disabled: 不启用 Profiling: 让pipeline提供详细的调试信息,在FrameDebugger中可以看到。 | m_DebugLevelProp |
Shader Variant Log Level | 当Unity在build完工程的时候,可以显示shader stripping和shader variants的相关信息。本属性就是控制这些信息的显示。属性值有三种:Disabled: Unity不显示任何的信息 Only Universal: 只显示和URP shader相关的信息 All: Unity显示所有的shader的信息 | m_ShaderVariantLogLevel |
3 Rendering in the Universal Render Pipeline
首先看一下在URP renderpipe中,如何渲染一帧的代码:
/*
UniversalRenderPipeline类的成员函数Render
UniversalRenderPipeline类继承自UnityEngine.Rendering.RenderPipeline类,
且UniversalRenderPipeline类是一个sealed类,所以它不能也不意图被继承派生
UniversalRenderPipeline.Render函数重载了基类的同名函数
UniversalRenderPipeline类有一部分定义在UniversalRenderPipeline.cs文件中,
这个文件(7.1.1版本),通过Package Manager下载之后,其目录在:
Library\PackageCache\com.unity.render-pipelines.universal@7.1.1\Runtime
*/
protected override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{
// BeginFrameRendering是基类RenderPipeline的静态成员函数
// 在开始使用camera进行渲染时,执行相关的回调
BeginFrameRendering(renderContext, cameras);
// 判断当前活跃的颜色空间,是否是线性颜色空间,如果是的话,光源也要使用线性亮度
GraphicsSettings.lightsUseLinearIntensity =
(QualitySettings.activeColorSpace == ColorSpace.Linear);
// 是否使用SRP Batcher进行合批处理
GraphicsSettings.useScriptableRenderPipelineBatching = asset.useSRPBatcher;
// 此方法是UniversalRenderPipeline类的提供的静态成员函数
// 顾名思义,就是用来设置每一帧用到的shader constants,此函数也在
// UniversalRenderPipeline.cs文件中定义
SetupPerFrameShaderConstants();
// SortCameras也是UniversalRenderPipeline类的成员方法,定义在
// UniversalRenderPipelineCore.cs文件中。这个方法是把传递进来的camera,
// 按其深度值进行排序,其深度值越大,离摄像机就越远,那就应该越早渲染,
// 所以要把它排在摄像机数组的前面。
SortCameras(cameras);
// 针对每一个camera,执行该camera应该要执行的rendering操作
foreach (Camera camera in cameras)
{
// BeginCameraRendering是基类RenderPipeline的静态成员函数
// 在开始使用某一个camera进行渲染时,执行相关的回调
BeginCameraRendering(renderContext, camera);
#if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER
// It should be called before culling to prepare material.
// When there isn't any VisualEffect component, this method has no effect.
// visual effect graph相关的,网址如下:
// https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@7.1/manual/index.html
VFX.VFXManager.PrepareCamera(camera);
#endif
// 此方法是UniversalRenderPipeline类的提供的静态成员函数
// 使用某一个camera进行渲染
RenderSingleCamera(renderContext, camera);
// EndCameraRendering是基类RenderPipeline的静态成员函数
// 在开始使用某一个camera进行渲染时,执行相关的回调
EndCameraRendering(renderContext, camera);
}
// EndFrameRendering是基类RenderPipeline的静态成员函数
// 在开始使用camera进行渲染时,执行相关的回调
EndFrameRendering(renderContext, cameras);
}
void SortCameras(Camera[] cameras)
{
Array.Sort(cameras, (lhs, rhs) => (int)(lhs.depth - rhs.depth));
}
public static void RenderSingleCamera(ScriptableRenderContext context, Camera camera)
{
// 获取到和本摄像机有关的拣选相关的参数
if (!camera.TryGetCullingParameters(IsStereoEnabled(camera),
out var cullingParameters))
return;
var settings = asset;
UniversalAdditionalCameraData additionalCameraData = null;
if (camera.cameraType == CameraType.Game ||
camera.cameraType == CameraType.VR)
camera.gameObject.TryGetComponent(out additionalCameraData);
// InitializeCameraData函数是UniversalRenderPipeline类的静态成员函数。
// 根据传递进来的各种参数最后返回一个CameraData类型变量,这个就是当前
// 渲染使用的摄像机的各种数据
InitializeCameraData(settings, camera, additionalCameraData, out var cameraData);
// SetupPerCameraShaderConstants函数是UniversalRenderPipeline类的静态成员函数。
// 根据当前的camera的数据属性,设置逐帧的着色器常量
SetupPerCameraShaderConstants(cameraData);
ScriptableRenderer renderer = (additionalCameraData != null) ?
additionalCameraData.scriptableRenderer :
settings.scriptableRenderer;
if (renderer == null)
{
Debug.LogWarning(string.Format(
"Trying to render {0} with an invalid renderer. Camera rendering will be skipped.",
camera.name));
return;
}
string tag = (asset.debugLevel >= PipelineDebugLevel.Profiling)
? camera.name: k_RenderCameraTag;
// 从command buffer 池中根据tag取得CommandBuffer对象
CommandBuffer cmd = CommandBufferPool.Get(tag);
using (new ProfilingSample(cmd, tag))
{
renderer.Clear();
renderer.SetupCullingParameters(
ref cullingParameters, ref cameraData);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
#if UNITY_EDITOR
// Emit scene view UI
if (cameraData.isSceneViewCamera)
ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
#endif
var cullResults = context.Cull(ref cullingParameters);
InitializeRenderingData(settings, ref cameraData,
ref cullResults, out var renderingData);
renderer.Setup(context, ref renderingData);
renderer.Execute(context, ref renderingData);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
context.Submit();
}
从上面的代码中可以看出:在一个 前向渲染器(forward renderer) 中。每渲染一帧的做法流程如下:
当在【Graphics Settings】面板中指定选中了URP render pipeline的时候,Unity将会使用URP去渲染所有的摄像机所观察的东西,包括game窗口,scene窗口,反射探针,inspector面板上的预览窗口。
3.1 Camera loop
从上面的代码中可以看出,在一个 摄像机循环(camera loop) 内,执行以下三步的操作:
- 拣选出你场景中需要渲染的objects。
- 创建渲染器所需的数据。
- 执行渲染操作,向framebuffer渲染出一个image。
再进一步细化上面的三步为:
- 配置用于确定拣选系统如何拣选灯光和阴影的参数。您可以使用自定义渲染器覆盖渲染管道的这一部分。
- 使用上一步中的拣选选参数,计算可见的渲染器, 阴影投射器(shadow caster) 和灯光的列表。 拣选参数和相机的 层距离(layer distances) 会影响拣选和渲染性能。
- 根据拣选操作的输出(culling output),URP asset,摄像机的质量设置(quality settings)。以及当前运行的平台来捕获信息,以构建渲染数据(RenderingData类对象),然后那渲染数据通知到渲染器
- 生成渲染通路列表(list of render pass),并根据渲染数据将它们排队以执行。 您可以使用自定义渲染器,覆盖掉URP提供的render pipe中的这一部分
- 执行队列中的每个渲染通路。渲染器将Camera拍摄到的图像,输出到帧缓冲区。