文章

渲染流程 URP LWRP

前言

通用渲染管道(URP)使用以下方式渲染场景:

  • 前向渲染器
  • URP随附的着色器的着色模型
  • 相机
  • UniversalRP资产

在Forward渲染器中,URP实现了一个渲染循环,该循环告诉Unity如何渲染框架。

URP渲染器为每个摄影机执行一个摄影机循环,该循环执行以下步骤:

  1. 剔除场景中的渲染对象
  2. 为渲染器生成数据
  3. 执行将图像输出到帧缓冲区的渲染器。

UniversalRP提供了可用于在渲染循环的开始和结束以及每个Camera循环的开始和结束执行代码的回调。

相机循环

Camera循环执行以下步骤:

步骤描述
设置筛选参数配置用于确定剔除系统如何剔除灯光和阴影的参数。可以使用自定义渲染器覆盖渲染管道的这一部分。
剔除使用上一步中的剔除参数计算相机可见的可见渲染器,阴影投射器和灯光的列表。剔除参数和“相机” 层距离会影响剔除和渲染性能。
建立渲染数据根据剔除输出,URP资产,摄像机的质量设置以及当前运行的平台来捕获信息,以构建信息RenderingData。渲染数据告诉渲染器摄像机和当前所选平台所需的渲染工作量和质量。
设置渲染器生成渲染通道列表,并根据渲染数据将它们排队以执行。可以使用自定义渲染器覆盖渲染管道的这一部分。
执行渲染器执行队列中的每个渲染过程。渲染器将Camera图像输出到帧缓冲区。

剔除

剔除是决定物体是否要在屏幕上渲染内容的过程。

在Unity中,剔除包括:

  • 视锥剔除:计算存在于相机的近平面和远平面之间的GameObject。
  • 遮挡剔除:计算哪些游戏对象隐藏在其他游戏对象之后,然后从渲染中排除它们。

Unity开始渲染时,它需要计算的第一件事就是渲染什么。这涉及拿起相机并从相机的角度执行剔除操作。剔除操作会返回可为Camera渲染的GameObjects和Lights列表。可脚本化渲染管道(SRP)稍后将在渲染管道中使用这些GameObject。

在SRP中,通常从摄影机的角度执行GameObject渲染。这是Unity用于内置渲染的Camera GameObject。SRP提供了许多开始使用的API。

通常流程如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Create an structure to hold the culling paramaters
ScriptableCullingParameters cullingParams;

//Populate the culling paramaters from the camera
if (!CullResults.GetCullingParameters(camera, stereoEnabled, out cullingParams))
    continue;

// if you like you can modify the culling paramaters here
cullingParams.isOrthographic = true;

// Create a structure to hold the cull results
CullResults cullResults = new CullResults();

// Perform the culling operation
CullResults.Cull(ref cullingParams, context, ref cullResults);

绘制

在可编写SRP时,应该在剔除过程之后进行绘制。当的SRP具有一组剔除结果时,它可以将相关的GameObjects渲染到屏幕上。

可以通过多种方式配置渲染管道以渲染场景,因此在实现场景之前需要做出许多决定。其中许多决定是由以下因素驱动的:

  • 要将渲染管道定位到的硬件。
  • 希望达到的特定外观。
  • 正在制作的项目类型。

例如,一个2D移动侧滚动游戏和一个3D高端PC第一人称视角游戏具有极大不同的约束,因此应该具有极大不同的渲染管线。做出实际决策的一些具体示例包括:

  • HDR与LDR(HDR vs LDR)
  • 线性与伽玛(Linear vs Gamma)
  • MSAA与后期处理抗锯齿(MSAA vs Post Process anti-aliasing)
  • 物理材料与简单材料(Physically-based Materials vs Simple Materials)
  • 照明与不照明(Lighting vs No Lighting)
  • 照明技术(Lighting technique)
  • 阴影技术(Shadowing technique)

Filtering

通常,GameObjects具有特定的分类。它们可以是不透明的,透明的,子表面等。Unity使用队列的概念来表示何时渲染GameObject。

还可以使用标准的Unity层进行过滤。

1
2
3
4
5
6
7
8
9
10
11
12
// Get the opaque rendering filter settings
var opaqueRange = new FilterRenderersSettings();

//Set the range to be the opaque queues
opaqueRange.renderQueueRange = new RenderQueueRange()
{
    min = 0,
    max = (int)UnityEngine.Rendering.RenderQueue.GeometryLast,
};

//Include all layers
opaqueRange.layerMask = ~0;

Draw Settings

使用过滤和剔除可以确定SRP应该渲染哪些GameObject,但是随后需要确定SRP如何渲染它们。SRP提供了多种选项来配置如何渲染通过过滤的GameObject。用于配置此数据的结构为DrawRenderSettings。此结构使可以配置许多东西:

  • 排序–渲染游戏对象的顺序,示例包括从后到前和从前到后。
  • Per-Renderer标志– Unity应该将哪些“内置”设置传递给Shader,其中包括per-GameObject Light Probes和per-GameObject Light贴图。
  • 渲染标志– SRP应该使用哪种算法进行批处理,例如实例化或非实例化。
  • Shader Pass – Shader Pass – SRP应该在当前绘制调用中使用哪个Shader Pass。
1
2
3
4
5
6
7
8
9
10
11
12
// Create the draw render settings
// note that it takes a shader pass name
var drs = new DrawRendererSettings(myCamera, new ShaderPassName("Opaque"));

// enable instancing for the draw call
drs.flags = DrawRendererFlags.EnableInstancing;

// pass light probe and lightmap data to each renderer
drs.rendererConfiguration = RendererConfiguration.PerObjectLightProbe | RendererConfiguration.PerObjectLightmaps;

// sort the objects like normal opaque objects
drs.sorting.flags = SortFlags.CommonOpaque;

提交绘制

现在我们具备了绘制的前置工作

  • Cull results
  • Filtering rules
  • Drawing rules

在SRP中,通常不渲染单个网格,而是发出一次一次渲染大量网格的调用。这样可以减少脚本执行的开销,并可以在CPU上快速,按任务执行。

1
2
3
4
5
// draw all of the renderers
context.DrawRenderers(cullResults.visibleRenderers, ref drs, opaqueRange);

// submit the context, this will execute all of the queued up commands.
context.Submit();

这会将GameObjects绘制到当前渲染目标中。可以使用命令缓冲区来切换渲染目标。

本文由作者按照 CC BY 4.0 进行授权