asset文件夹路径 unity_[Universal RP]Unity通用渲染管线学习

本文档介绍了Unity的通用渲染管线Universal RP,包括其开源、单Pass Forward Rendering的优势,以及与内置管线的区别。详细分析了渲染管线的代码,讲解了如何使用和扩展URP,涉及Render方法和RenderSingleCamera方法的实现细节。此外,讨论了URP的提升和不足,如不支持多相机叠加和延迟渲染。
摘要由CSDN通过智能技术生成

cfa48350ddc54ad780ea5ed20977cdbe.png

Unity正式加入了Universal RP(通用渲染管线),这里会记录一些官方文档,并分析管线的代码,文中使用Unity2019.3.0b1,Universal RP 7.0.1。

可编程渲染管线

为了解决仅有一个默认渲染管线,造成的可配置型、可发现性、灵活性等问题。Unity在管线设计的概念上做了转移,决定在C++端保留一个非常小的渲染内核,让C#端可以通过API暴露出更多的选择性,也就是说,Unity会提供一系列的C# API以及内置渲染管线的C#实现;这样一来,一方面可以保证C++端的代码都能严格通过各种白盒测试,另一方面C#端代码就可以在实际项目中调整,有任何问题也可以方便地进行调试。

9b542f068a87dfafd83ffa7efa3b38b4.png

新的管线对用户而言主要是C# 端的API以及由这些API编写的一系列定制化的内置渲染管线。而在内部实现上,引擎C++端会负责多线程实现性能关键的部分,如上图所示,而C#端负责更高层的渲染指令调度。

889c0559cf1e5ad9cf43c973ff22a0f4.png
可编程渲染管线的使用层设计

用户可以直接使用开源的内置管线,或者在内置管线的基础上进行修改,甚至直接编写定制化的管线。具体使用上渲染管线在工程中会生成特定的Asset,如下图所示,这个Asset序列化了这条管线的一些公共设置变量,并负责在运行时创建实际的渲染上下文;当这个Asset的设置变量在运行时发生变化,引擎会销毁当前上下文然后重新创建管线。

可编程渲染管线是URP的基础,通过它我们可以知道unity中怎么实现最基本的渲染,unity对渲染管线API封装程度。

详解可编程脚本渲染管线SRP - Unity Connect​connect.unity.com
0994739b74b3676d604c7c154ec69109.png
Scriptable Render Pipeline Overview – Unity Blog​blogs.unity3d.com
f1953ef7999696d764375c4e194dd29a.png

通用渲染管线Universal RP

LWRP是URP之前的名称,两者基本没有区别,URP相对LWRP的变化主要是把PostProcessing集成到内部了。

Unity轻量级渲染管线LWRP源码及案例解析(上) - Unity Connect​connect.unity.com
55d4029c9284427bf5da3f54c34d9148.png
Unity轻量级渲染管线LWRP源码及案例解析(下)​connect.unity.com

Unity轻量级渲染管线LWRP源码及案例解析,讲解了URP的使用方法和拓展方法,里面有对SRP、URP的一些说明,URP与内置管线的对比,URP的源码结构。

在继续看源码细节之前,先看看URP的主要提升(相对于内置管线),和不完善的地方。

提升:

1 开源

可编程渲染管线最大的好处就是开源,对于有能力的团队,可以选择在SRP的基础上写自己的管线。而使用Unity提供的管线模板URP或HDRP,也可以把他们从Package包中提出到Asset中做更改,上面的文章有提到修改的注意事项(其实就是记着把Shader中的include路径,和代码中的Shader.Find之类的路径改一下),但是并不推荐这么做,因为版本更新的维护是噩梦。开源意味着容易定位到问题,对调试非常友好。

2 渲染路径改为单Pass Forward Rendering

内置管线的多Pass Forward Rendering,会在多光源时对额外的光源使用新的FowardAdd Pass计算,Pass数量是影响物体的光源数量,最大值为8。

URP的单Pass Forward Renderering,会将光源一次性传入Forward Pass,但由于单Pass能够传的数据有限,现在最多支持一个直线光外加4个其他光源。

这样做虽然并不完美,但多光源场景中DrawCall数量会大量下降。

3 拓展性(非代码修改)

URP在渲染队列中嵌入了拓展入口,相当于之前的CommandBuffer的可视化操作。上面的文章中有详细的使用方法。

用新的设计取代了GrabPass的结构,在Opaque渲染之后可以截出一张RenderTexture,提供给之后使用。

4 SRP Batcher

提供了一种新的批处理方式,基于Shader的批处理。不过这个技术还不是正式功能,有些局限,不支持Skinned Meshes、Material Property Blocks。

缺点:

1 不支持多相机叠加

这是很重要的功能,如果真用到了,就去改源码吧,要不等之后更新。

2 Defferred Renderring

现在URP里面没有延迟渲染,也没有时域抗锯齿TAA。

一个SRP代码示例

我们先看 详解可编程脚本渲染管线SRP - Unity Connect 中的最后一个例子,半透明渲染。

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;

// RenderPipelineAsset继承自ScriptableObject,用于提供序列化的渲染参数、并根据参数生成管线实例
[ExecuteInEditMode]
public class TransparentAssetPipe : RenderPipelineAsset
{
    
#if UNITY_EDITOR
    // 编辑器中创建ScriptableObject
    [UnityEditor.MenuItem("SRP-Demo/03 - Create Transparent Asset Pipeline")]
    static void CreateBasicAssetPipeline()
    {
    
        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);

            // 设置渲染相机(设置渲染目标, view/projection 矩阵和每相机内置shader变量).
            context.SetupCameraProperties(camera);

            // 清理深度缓存
            var cmd = new CommandBuffer();
            cmd.ClearRenderTarget(true, false, Color.black);
            context.ExecuteCommandBuffer(cmd);
            cmd.Release();

            // 使用一个指定的着色器通道,新建渲染设置
            var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
            settings.sorting.flags = SortFlags.CommonOpaque;

            // 获取不透明渲染过滤器设置
            var filterSettings = new FilterRenderersSettings(true) {
     renderQueueRange = RenderQueueRange.opaque };
            // 绘制所有渲染器
            context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);

            // 绘制天空盒
            context.DrawSkybox(camera);

            // 绘制半透明物体(着色器通道还是绘制不透明物体时用到的)
            settings.sorting.flags = SortFlags.CommonTransparent;
            filterSettings.renderQueueRange = RenderQueueRange.transparent;
            context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);
            
            // 提交渲染上下文
            context.Submit();
        }
    }
}

渲染入口点为RenderPipeline类中的Render函数,参数为相机列表和渲染上下文,在这个函数的最后提交渲染上下文,完成渲染。填充渲染上下文的过程中,Unity封装好了一些方法,包括剔除操作、CommandBuffer的一系列指令、绘制渲染器等。

Universal RP

推荐先熟悉Universal RP的使用,再去看代码的实现,这样效率会更高。

Universal RP 7.0的文档​docs.unity3d.com

Universal RP的依赖Package有两个,CoreRPLibrary是URP和HDRP都用到的一些工具,ShaderGraph是shader的可视化节点编辑器,之前的PostProcessing已经集成到内部了。

32bc2fba788ea613c1271e90e9183a49.png

6a1d0f5df8a331cbbe5a807d01d3b83d.png

5f83557309706fd942f21e9ee9db25bc.png

Render方法

Universal RP的主要实现就在Universal RP的Runtime文件夹中,我们从渲染入口点开始看实现细节。

a514ee9eaa3c897ba6f9b837504babcd.png
UniversalRenderPipeline类中的Render方法

61ad02b1fe680e83f123c46a3d7f65ff.png
一个Rendering Loop过程

整体结构非常简单,设置GraphicSetting参数,设置每帧Shader中的Global 变量,相机排序,相机遍历,每相机渲染。

首先看一下四个方法BeginCameraRen

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值