翻译官网"//**"为备注
官网地址:https://blogs.unity3d.com/cn/2018/01/31/srp-overview/
在2018.1 beta中引入的Scriptable Render Pipeline(SRP)是一种在Unity中配置和执行渲染的方法,该方法由C#脚本控制。在编写自定义渲染管道之前,了解渲染管道时我们究竟意味着什么是很重要的。
“渲染管道”是用于将对象放到屏幕上的许多技术的总称。它涵盖了非常高的水平:
除了这些高级概念之外,每个职责都可以根据您希望如何执行来进一步细分。例如,渲染对象可以使用以下方式执行:
编写自定义SRP时,这些是您需要做出的决策。每种技术都需要考虑许多权衡因素。
本文中讨论的所有功能都包含在GitHub上的演示项目中 // git地址:https://github.com/stramit/SRPBlog.git
使用SRP时,您需要定义一个控制渲染的类; 这是您将要创建的渲染管道。入口点是对“渲染”的调用,它采用渲染上下文(如下所述)和要渲染的摄像机列表。
1 2 3 4 |
public class BasicPipeInstance : RenderPipeline { public override void Render(ScriptableRenderContext context, Camera[] cameras){} } |
SRP使用延迟执行的概念。作为用户,您可以构建一个命令列表,然后执行它们。用于构建这些命令的对象称为“ScriptableRenderContext”。当您使用操作填充上下文时,您可以调用“提交”以提交所有排队的绘制调用。
剔除是确定在屏幕上呈现什么的过程。
在Unity Culling中包含:
渲染开始时,需要计算的第一件事就是渲染。这涉及从相机的角度拍摄相机并执行剔除操作。剔除操作返回有效为相机渲染的对象和灯光列表。然后,这些对象将在渲染管道中使用。
剔除SRP(Culling in SRP)
在SRP中,通常从Camera的角度执行对象渲染。这是Unity用于内置渲染的相同对象。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); |
现在可以使用已填充的剔除结果来执行渲染。
现在我们有一组剔除结果,我们可以将它们渲染到屏幕上。
但是有很多方法可以配置事物,因此需要预先做出一些决定。其中许多决策将由以下因素驱动:
例如,想想一个移动2D sidescroller游戏与PC高端第一人称游戏。这些游戏具有非常不同的约束,因此将具有截然不同的渲染管线。可能做出的真正决策的一些具体例子:
在编写渲染管道时做出这些决定将帮助您确定创作时所处理的许多约束。
过滤 (渲染桶和层)(Filtering: Render Buckets and Layers)
通常,当渲染对象具有特定分类时,它们是不透明的,透明的,子表面或任何数量的其他类别(opaque, transparent, sub surface, or any number of other categories)。Unity使用队列概念来表示何时应该呈现对象,这些队列形成将放置对象的桶(源自对象上的材料)。从SRP调用渲染时,您可以指定要使用的存储区范围。
除了存储桶之外,标准Unity层也可用于过滤。
这提供了在通过SRP绘制对象时进行额外过滤的功能。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 获取渲染设置 var opaqueRange = new FilterRenderersSettings();
//设置不透明渲染区间 opaqueRange.renderQueueRange = new RenderQueueRange() { min = 0, max = (int)UnityEngine.Rendering.RenderQueue.GeometryLast, };
//设置层(~0为全部层) opaqueRange.layerMask = ~0; |
绘制设置:确定什么对象需要绘制(Draw Settings: How things should be drawn)
使用过滤和剔除确定应该渲染的内容,但是我们需要确定它应该如何渲染。SRP提供了多种选项来配置应如何呈现通过过滤的对象。用于配置此数据的结构是“DrawRenderSettings”结构。此结构允许配置许多内容:
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(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; |
最终绘制(Drawing)
现在我们有三个需要发出绘图调用的东西:
我们可以发起绘制!与SRP中的所有内容一样,绘制调用作为对上下文的调用发出。在SRP中,通常不会渲染单个网格,而是发出一次调用渲染大量网格的调用。这减少了脚本执行开销,并允许在CPU上快速执行作业。
为了发出绘图调用,我们结合了我们一直在构建的函数。
1 2 3 4 5 6 7 |
// 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(); |
这会将对象绘制到当前绑定的渲染目标中。如果您愿意,可以使用命令缓冲区切换渲染目标。
---感谢google翻译,有道翻译
可编程渲染管线,把部分渲染控制提供权给了开发者,开发者可以根据自己的项目需求,设置符合自己的渲染管线,减少了引擎兼容引起的一些效率问题。
还在学习中,共勉。附一个官网的代码,加我自己的备注。
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
///透明渲染管线
[ExecuteInEditMode]
public class TransparentAssetPipe : RenderPipelineAsset
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("SRP-Demo/03 - Create Transparent Asset Pipeline")]
static void CreateBasicAssetPipeline()
{
// 创建RenderPipelineAsset实例,并保存在本地,用于在Graphics设置界面设置
var instance = ScriptableObject.CreateInstance<TransparentAssetPipe>();
UnityEditor.AssetDatabase.CreateAsset(instance, "Assets/SRP-Demo/3-TransparentAssetPipe/TransparentAssetPipe.asset");
}
#endif
protected override IRenderPipeline InternalCreatePipeline()
{
return new TransparentAssetPipeInstance();
}
}
public class TransparentAssetPipeInstance : RenderPipeline
{
//开始渲染
public override void Render(ScriptableRenderContext context, Camera[] cameras)
{
base.Render(context, cameras);
foreach (var camera in cameras)
{
// 设置剔除
ScriptableCullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
//生成剔除规则
CullResults cull = CullResults.Cull(ref cullingParams, context);
// 设置显然对象
// 每个生效的镜头
context.SetupCameraProperties(camera);
// 清空屏幕指令
var cmd = new CommandBuffer();
//public void ClearRenderTarget (bool clearDepth, bool clearColor, Color backgroundColor);
//@param clearDepth 清空深度数据,与深度剔除有关,不清空则深度信息还在,无法在低于深度的区域绘制新数据
//@param clearColor 清空颜色数据,清空颜色,可不清楚,深度清楚后,会重新写入颜色数据
//@backgroundColor 清空后默认颜色
cmd.ClearRenderTarget(true, false, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// 使用BasicPass绘制不透明对象
var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
settings.sorting.flags = SortFlags.CommonOpaque;
//创建过滤设置,即指定BasicPass绘制不透明区域
var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);
// 绘制天空盒子
context.DrawSkybox(camera);
// 绘制透明对象,使用BasicPass绘制不透明对象
settings.sorting.flags = SortFlags.CommonTransparent;
filterSettings.renderQueueRange = RenderQueueRange.transparent;
context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);
//提交
context.Submit();
}
}
}