Unity 可编程渲染管线

文章目录

  • 可编程渲染管线 Scriptable Render Pipeline
    • 什么是可编程渲染管线SRP
    • 什么是SRP Core
  • SRP入门 Getting Started
    • 概述
      • SRP Asset
      • SRP Instance
    • SRP要解决的问题
      • 问题
      • 解决方案
    • SRP Asset
      • SRP Asset 例子
    • SRP Instance
      • 基础管线 A basic pipeline
    • SRP Context
  • 用SRP渲染 Rendering with SRP
    • 裁剪 Culling
    • 绘制 Drawing
      • 过滤:渲染队列和层 Filtering: Render Buckets and Layers
      • 渲染设置 Draw Settings: How things should be drawn
      • 绘制 Drawing
  • XR应用SRP (Virtual Reality)
  • 摄像机组件 Camera Components
    • Free Camera
    • Camera Switcher

可编程渲染管线 Scriptable Render Pipeline

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tUm1QF1U-1581473895125)(https://blogs.unity3d.com/wp-content/uploads/2018/01/image5_rs.png)]

什么是可编程渲染管线SRP

Scriptable Render Pipeline(SRP),提供一组特性,让你可以完全的控制Unity的渲染流程,并提供工具创建流行的,真实的图形。

SRP允许通过编写C#代码来控制每帧的渲染。不像内建的渲染管线是一个渲染的黑盒子,SRP让你可以看到和精确控制渲染过程。

Unity也提供了2种预建的SRP,可以在项目种作为自定义SRP的基础:

  • Universal Render Pipeline 提供了从手机平台到高端主机和PC平台的图形渲染
  • High Definition Render Pipeline 利用PBR技术,为兼容Compute Shader的显卡平台提供逼真的图形渲染。

与其从头开始实现自己的SRP,建议基于URP或HDRP根据自己的需求进行修改。

什么是SRP Core

SRP Core 是一组API,将内部渲染和配置暴漏给你,这可以让你精确控制渲染如何工作。

SRP API 提供了一组与一些Unity结构相似的接口:

  • Lights
  • Materials
  • Cameras
  • Command Buffers

SRP 改变的是与Unity交互的方式。基于效率的考虑,当你实现自己的SRP时,需要一系列的Renderer,而不是单独实现某个独立的组件。

SRP入门 Getting Started

概述

从上层来看,SRP可以被分成2部分,SRP Asset 和 SRP Instance。当实现自己的SRP时,需要实现这两部分。

SRP Asset

SRP Asset 是用来为管线存储需要的配置数据,包括:

  • Game Object 是否可以投射阴影
  • 使用哪个级别的Shader Quality
  • 阴影距离
  • 默认的材质配置

SRP Instance

SRP Instance 是真正执行渲染的类。当Unity发现使用了SRP,它会检查当前的SRP Asset 并请求它提供渲染实例,而SRP Asset 必须要返回一个包含 Render 函数的实例。通常该Instance也要将SRP Asset的一些配置缓存下来方便使用。

Instance 缓存了管线的配置,在Render方法中,Unity可以执行下列行为:

  • 清理帧缓存 Clearing the framebuffer
  • 执行场景裁剪
  • 渲染一组游戏对象
  • 执行framebuffer之间的拷贝
  • 渲染阴影
  • 执行后效

SRP要解决的问题

渲染管线是一系列的步骤来将对象绘制到屏幕上,而SRP则是将这些步骤交给你可以编程进行控制。

问题

Unity提供了一些内建的管线使用。包括适用于移动平台和VR的前向渲染,以及适用于高端的延迟着色。这些解决方案像个黑盒,方便的同时有以下问题:

  • 它们只能按照Unity设计的来工作
  • 它们是通用的,意味着它们要做所有的事情,同时意味着所有事情都不是最优的
  • 它们的可配置度很低,是黑盒工具,仅可以在预定义的点注入渲染指令
  • 扩展和修改非常容易导致错误,因为内部一点小改动,都会导致对外部的很大影响
  • Unity对一些BUG难以进行修复,因为这些修复可能会导致现有项目无法工作

解决方案

SRP的推出就是为了解决上面的问题。将内建的渲染过程改为可以针对每个项目编程控制的。

SRP Asset

SRP Asset 包含了一组接口用来对渲染管线进行配置。当Unity第一次渲染时,会调用其 InternalCreatePipeline 方法创建渲染实例。

SRP实际上是一个 ScriptableObject,所以它是一个资源文件,可以进行版本控制。可以在Project窗口中创建SRP Asset,也可以通过脚本创建并通过AssetDatabase API进行保存。

在ProjectSettings>Graphics中设置启用自己的SRP Asset。

除了返回渲染实例和处理配置数据外,还可以通过SRP Asset提供一些辅助函数:

  • 创建3D对象时的默认材质
  • 创建2D对象时的默认材质
  • 创建粒子时的默认材质
  • 创建地形时的默认材质

这主要是为了让编辑器正确工作。如果希望在新的管线的编辑器像Unity的管线编辑器一样工作,则需要实现这些。

SRP Asset 例子

Asset 包含了一些渲染属性,以及返回一个渲染实例来渲染场景。如果设置改变,则Unity会销毁渲染实例,并创建新的,在下一帧进行渲染。

下面是一个SRP Asset 的例子。包含了SRC Instance 清除屏幕时用的颜色,以及在编辑器中创建SRC Asset的逻辑,创建完后可以在Graphics设置窗口中设置。

[ExecuteInEditMode]
public class BasicAssetPipe : RenderPipelineAsset
{
	public Color clearColor = Color.green;
	
#if UNITY_EDITOR
	[MenumItem("SRP-Demo/01 - Create Basic Asset Pipeline")]
	static void CreateBasicAssetPipeline()
	{
		var instance = ScriptableObject.CreateInstance<BasicAssetPipe>();
		UnityEditor.AssetDatabase.CreateAsset(instance, "Assets/BasicAssetPipe.asset");
	}
#endif
	// 返回渲染实例
	protected override IRenderPipeline InternalCreatePipeline()
	{
		return new BasicPipeInstance(clearColor);
	}
}

SRP Instance

SRP Asset 控制渲染配置,SRP Instance 则时渲染入口。当开发SRP时,需要实现该类,并在该类中实现所有的渲染逻辑。

最简单的,SRP Instance 只需要包含一个接口:Render。可以理解为这时空白的画板,可以在里面自由地用任何方式进行渲染。Render 函数有两个参数:

  • ScriptableRenderContext 是一个指令缓存,可以推入渲染操作来执行。
  • 一组渲染用的摄像机。

基础管线 A basic pipeline

前面的SRP Asset返回的Rendering Instance在下面实现:

public class BasicPipeInstance : RenderPipeline
{
	private Color m_ClearColor = Color.black;
	
	public BasicPipeInstance(Color clearColor)
	{
		m_ClearColor = clearColor;
	}
	
	public override void Render(ScriptableRenderContext context, Camera[] cameras)
	{
		base.Render(context, cameras);
		
		// 将屏幕清理成配置的颜色
		var cmd = new CommandBuffer();
		cmd.ClearRenderTarget(true, true, m_ClearColor);
		context.ExecuteCommandBuffer(cmd);
		cmd.Release();
		context.Submit();
	}
}

管线仅简单的用SRP Asset配置的颜色,清理屏幕。需要注意几点:

  • SRP 使用Unity的CommandBuffer来执行许多操作(这里是ClearRenderTarget)。
  • SRP 用传进来的context执行CommandBuffers。
  • 最后,要调用context.Submit,来执行我们添加到context指令队列中的指令。

Render函数是我们进行渲染的地方,在这里我们要执行裁剪,过滤,改变renter target,绘制,等。

SRP Context

SRP渲染使用延迟执行的概念。我们建立了一个指令列表,并执行该列表。指令列表即Render参数传进来的ScriptableRenderContext对象context。

当指令添加到context队列中后,可以调用它的Submit来提交这些指令,这些指令会被组合成一个Command Buffer并执行。

ScriptableRenderContext的API可以参考:API documentation.

用SRP渲染 Rendering with SRP

裁剪 Culling

裁剪负责找出哪些需要被渲染到屏幕上。在Unity中,裁剪包括:

  • Frustum Culling 视锥体裁剪。找出所有在摄像机近裁剪面和远裁剪面之间的对象。
  • Occlusion Culling 遮挡剔除。找到被其它对象遮挡的对象,并将其排除出渲染对象列表。详细参考:Occlusion Culling.

Unity开始渲染后,第一件要做的事情就是要决定哪些对象需要被渲染,使用相关的摄像机进行裁剪。裁剪操作返回一个该摄像机需要渲染的对象和光源列表。SRP在之后的渲染中使用这些数据。

SRP提供了一些API用来进行裁剪,通常像下面:

ScriptableCullingParameters cullingParams;
// 从摄像机获取裁剪参数
if(!CullResults.GetCullingParameters(camera, stereoEnabled, out cullingParams))
    continue;
// 如果需要,可以修改裁剪参数
cullingParams.isOrthographic = true;
// 创建保存裁剪结果的结构体
CullResults cullResults = new CullResults();
// 执行裁剪
CullResults.Cull(ref cullingParams, context, ref culResults);
// 下面开始渲染
// render...

绘制 Drawing

SRP中,裁剪完成后,就可以将相关的游戏对象列表绘制到屏幕了。

可以有很多种方法进行渲染,因此在实现之前,要先决定绘制策略。这些策略包括:

  • 要执行渲染的硬件
  • 要达到的渲染效果
  • 项目的类型

例如,移动端2D卷轴游戏和3D高端PC第一人称游戏是完全不同的渲染管线。下面是一些需要做出的选择的例子:

  • HDR vs LDR 高动态范围光 vs 低动态范围光
  • Linear vs Gamma 线性 vs 伽马 空间
  • MSAA vs Post Processing anti-aliasing 多重屏幕抗锯齿 vs 后效抗锯齿
  • Physically-based Materials vs Simple Materials 基于物理的材质 vs 简单材质
  • Lighting vs No Lighting 是否有光照
  • Lighting Technique 采用哪种光照技术
  • Shadow Technique 采用哪种阴影技术

这些决策可以帮助我们在实现管线时决定应该有哪些限制。

下面的例子简单的渲染了一些不带光照,不透明的对象。

过滤:渲染队列和层 Filtering: Render Buckets and Layers

通常,每个Game Object都有特定的类型,不透明,半透明,次表面,等。Unity在渲染时将对象根据其类型,放入对应的队列来进行管理(根据对象的材质)。SRP渲染时,需要指定要渲染哪些队列。(原文是桶,感觉队列更容易理解)

除了队列,还可以用Unity的层Layer来进行过滤。

// 获取不透明过滤器对象
var opaqueRange = new FilterRenderersSettings();
// 设置不透明渲染队列范围
opaqueRange.renderQueueRange = new RenderQueueRange()
{
    min = 0,
    max = (int)UnityEngine.Rendering.RenderQueue.GeometryLast,
};
// 包括所有的层
opaqueRange.layerMask = ~0;

渲染设置 Draw Settings: How things should be drawn

通过裁剪和过滤确定了哪些对象将要被渲染,然后需要确定如何渲染它们。SRP提供了多种选项来配置对象如何进行渲染。配置渲染可以通过结构体 DrawRenderSettings。可以进行如下的配置:

  • Sorting 排序,以什么样的顺序进行渲染,比如从前向后,或从后向前(基于摄像机距离)。
  • Per-Renderer flags 哪些内建的设置需要传递给shader,包括像逐对象的光照探针,逐对象的光照贴图。
  • Rendering flags SRP使用哪种算法合批,比如instancing或non-instancing。
  • Shader Pass 当前的DrawCall使用哪个Shader Pass。
// 创建渲染设置
// 需要shader pass的名字
var drs = new DrawRendererSettings(myCamera, new ShaderPassName("Opaque"));
// 开启instancing
drs.flag = DrawRendererFlags.EnableInstancing;
// 指定为渲染传递光照探针和光照贴图
drs.rendererConfiguration = RendererConfiguration.PerObjectLightProbe | RendererConfiguration.PerObjectLightmaps;
// 按照不透明物体的渲染顺序排序
drs.sorting.flags = SortFlags.CommonOpaque;

绘制 Drawing

现在,我们有三样数据要交给DrawCall:

  • Cull Results 裁剪结果
  • Filtering rules 过滤规则
  • Drawing rules 绘制规则

现在,我们可以进行DrawCall了。通过SRP Context的接口进行调用。在SRP中,不需要单独渲染一个Mesh,而是调用接口一次渲染一批Mesh:

// 绘制所有的renderers
context.DrawRenderers(cullResults.visibleRenderers, ref drs, opaqueRange);
// 提交渲染
context.Submit();

这回将对象渲染到当前的Render Target,也可以使用Command Buffer来切换Render Target。

XR应用SRP (Virtual Reality)

要在SRP中应用VR,开启VR并在PlayerSettings中选择VR SDK。此外,可以通过SRP提供的XRGraphicsConfig类来配置VR。现在,XRGraphicsConfig提供了XRSettings接口,将会扩展以适配各种XRSDK子系统。

摄像机组件 Camera Components

Free Camera

Free Camera组件提供了简单的自由摄像机实现。将该组件添加到摄像机后,可以使用键盘,鼠标,或手柄,在运行时控制位置和朝向。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jDrw8Qho-1581473895127)(https://docs.unity3d.com/Packages/[email protected]/manual/Images/FreeCamera1.png)]

属性:

  • Look Speed Controller 用手柄控制摄像机旋转的速度
  • Look Speed Mouse 用鼠标控制摄像机旋转的速度
  • Move Speed 摄像机移动速度
  • Move Speed Increment 修改摄像机移动速度时的增量。当场景太大,当前的移动速度无法很快的遍历场景时有用。自动加速???
  • Turbo 当按下”Fire1“按键时,移动速度会乘上该值

Camera Switcher

Camera Switcher 允许定义一个摄像机列表,并能在Debug运行时,进行切换。当需要设置不同的视角来进行剖析,而且可以方便的切换对比,而保证位置不变。

属性:

  • Cameras 将挂有Camera组件的Game Object拖动来添加摄像机到列表中。Debug Window可以在这些摄像机列表中进行切换。

你可能感兴趣的:(Unity 可编程渲染管线)