unity 2018可编程渲染管线

翻译官网"//**"为备注

官网地址:https://blogs.unity3d.com/cn/2018/01/31/srp-overview/

在2018.1 beta中引入的Scriptable Render Pipeline(SRP)是一种在Unity中配置和执行渲染的方法,该方法由C#脚本控制。在编写自定义渲染管道之前,了解渲染管道时我们究竟意味着什么是很重要的。

什么是渲染管道

“渲染管道”是用于将对象放到屏幕上的许多技术的总称。它涵盖了非常高的水平:

  • 剔除
  • 渲染对象  
  • 后期处理

除了这些高级概念之外,每个职责都可以根据您希望如何执行来进一步细分。例如,渲染对象可以使用以下方式执行:

  • 多次渲染
    • 每个物体每个光通过一次   //单渲染对象,每个光源渲染一次(有上限)
  • 单通
    • 每个对象一次通过              //单渲染对象仅进行单次渲染
  • 递延
    • 将表面属性渲染为g缓冲区,执行屏幕空间照明     //先行把结果放入缓冲区,再经光照数据处理后渲染

编写自定义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”。当您使用操作填充上下文时,您可以调用“提交”以提交所有排队的绘制调用。

 

剔除(Culling

剔除是确定在屏幕上呈现什么的过程。

在Unity Culling中包含:

  • Frustum culling:计算相机近距离和远距离平面之间存在的对象。
  • Occlusion culling:计算隐藏在其他对象后面的对象并将其从渲染中排除。有关更多信息,请参阅Occlusion 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);

现在可以使用已填充的剔除结果来执行渲染。  

 

渲染(Drawing)

现在我们有一组剔除结果,我们可以将它们渲染到屏幕上。

但是有很多方法可以配置事物,因此需要预先做出一些决定。其中许多决策将由以下因素驱动:

  • 根据硬件确定渲染管线
  • 实现的特定外观和感觉
  • 制作的项目类型

例如,想想一个移动2D sidescroller游戏与PC高端第一人称游戏。这些游戏具有非常不同的约束,因此将具有截然不同的渲染管线。可能做出的真正决策的一些具体例子:

  • HDR vs LDR               //HDR比LDR支持更高的数据位数,则计算数据更细化,渲染效果更好
  • Linear vs Gamma      //Gamma(伽马矫正)针对非线性空间设计进行矫正,使不同监视器的呈现相同的效果。主要用在PC     
  • MSAA vs Post Process AA  //多重采样抗锯齿对比后处理抗锯齿,MS为当前帧计入缓冲区,Post Process为下一帧计入缓冲区
  • PBR Materials vs Simple Materials  //Physically-Based Rendering 更接近于真实,同时消耗更大,制作更复杂
  • Lighting vs No Lighting
  • Lighting Technique
  • Shadowing Technique

在编写渲染管道时做出这些决定将帮助您确定创作时所处理的许多约束。

过滤 (渲染桶和层)(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”结构。此结构允许配置许多内容:

  • Sorting - 应该呈现对象的顺序,示例包括从前到后和从前到后。
  • Per Renderer flags - “内置”设置应该从Unity传递到着色器,这包括每个对象光探测器,每个对象光照贴图等。
  • Rendering flags - 应该使用什么算法进行批处理,实例化和非实例化。
  • 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(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();
        }
    }
}

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