whoimi

A geek blog

View on GitHub

链接:Scriptable Render Pipeline Overview

Scriptable Render Pipeline Overview

>unity2018当中介绍了可编程的渲染管线(SRP)。SPR可以通过c#来控制unity中渲染的配置和实现。在了解用户可以定制的渲染管线之前,需要先知道我们所谈论的渲染管线是什么。

##什么是渲染管线

​ 渲染管线是一个概括性的术语,用来概括将对象(Object)绘制到屏幕上的一系列的技术。这是一个高度概括的概念,包括了:

渲染入口点(Rendering entry point)

​ 使用SRP时,你需要定义一个类用来控制渲染;渲染管线就是通过这个类来创建的。入口点是对”Render”方法的一次调用,每一次渲染都有不同的渲染上下文(Render Context,下文解释)和需要渲染的摄像机。

public class BasicPipeInstance : RenderPipeline
{
//context 渲染上下文 ,cameras 摄像机列表
   public override void Render(ScriptableRenderContext context, Camera[] cameras){}
}

渲染管线上下文(Render Pipeline Context)

​ SPR(脚本化渲染管线)渲染使用了延迟执行的概念。首先建立一系列的命令,然后统一执行。通过ScriptableRenderContext类来建立这一系列命令。当用一系列操作填充了这个上下文对象之后,可以 通过“submit”方法,来一次性提交所有drawcall。

​ 例子:使用CommandBuffer清空渲染目标:

// Create a new command buffer that can be used
// to issue commands to the render context
var cmd = new CommandBuffer();

// issue a clear render target command
cmd.ClearRenderTarget(true, false, Color.green);

// queue the command buffer
context.ExecuteCommandBuffer(cmd);

剪裁Culling

剪裁用来确定哪些内容需要渲染的屏幕上。

Unity中剪裁包含:

渲染开始时,需要决定哪些内容需要被渲染。这需要使用摄像机的透视图执行剪裁操作。剪裁结果是一个对象列表和光照列表。这些内容在接下来的渲染管线当中使用。

在SRP当中执行剪裁

在SRP当中你通常需要摄像机的透视来完成渲染。unity内置的渲染也是使用同一个摄像机。SRP提供了一系列剪裁API。

一般的剪裁流程:

// 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);

之后可以进行下一步渲染。

Drawing 绘制

现在的到了剪裁结果,可以进行进一步渲染。

这里有很多种配置方法,有下面内容决定:

过滤:桶和层

不同的对象有不同的类型,可以是透明不透明等。Unity使用队列的概念来决定对象渲染的时机。这些队列构成了桶,渲染对象将会保存在桶中(类似桶排序)。当我们使用SRP时,我们可以决定哪个范围的桶可以被渲染。

除了桶之外,标准的分层也可以用于过滤。

例子:

// 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;

绘制设置:物体如何被绘制

之前的过滤和剪裁都是决定了哪些内容需要被渲染。接下来决定这些物体如何被渲染。SRP提供了一系列的操作,对通过过滤的物体进行渲染配置。配置这些数据的结构是:DrawRenderSettings。这个结构允许以下内容的配置:

// Create the draw render settings
// note that it takes a shader pass name
var drs = new DrawRendererSettings(Camera.current, 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;

绘制

现在完成了:

我们需要执行一个draw call。一个draw call就是对上下文的一次调用。在SRP中通常不渲染独立的网格,除非你需要一次性绘制很多。这减小了开销,同时保证了CPU的快速执行。

发布draw call

// 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();

这会把对象渲染到当前绑定的渲染目标。你可以使用一个command buffer来切换渲染目标。