URP学习之七--RenderFeature

Posted shenyibo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了URP学习之七--RenderFeature相关的知识,希望对你有一定的参考价值。

Unity的URP给了我们扩展渲染Pass的接口--RenderFeature,我们之前在讲URP-ForwardRenderer的时候提到过RenderFeature,这个东西是可以用来扩展Pass的。RenderFeature是依附于ForwardRenderer的,如下图所示:

技术图片

 

 

 现在我们会看到RendererFeatures的列表是空的,我们来添加一个,点击加号,我们会发现只有一个RenderObjects可以选择,我们可以先用这个RenderObjects的RenderFeature来熟悉一下一个Feature是怎么执行的。添加后点击添加的条目,会有以下参数:

技术图片

 

我们首先看这个Feature怎么用:创建一个Unlit材质,将Pass的Name修改为"TestPass",然后将ShaderPasses中的PassName设置为“TestPass“,如下图:

 

 

 技术图片

 

 这样,我们就能正确的通过其他Pass来渲染这个物体了,这个Pass通过我们自己在Shader中的自定义可以实现各种效果,比如我们实现一个多Pass描边,继续刚才我们的例子,因为我们将原来的PassName改为了Feature的PassName(”TestPass“),所以URP就不会调用UniversalForwardPass了。如果我们把UniversalForwardPass加回来,同时有UniversalForwardPass和TestPass两个Pass,就等于这个物体会在两个Pass中被渲染,即我们以前内置管线的多Pass渲染,通过这种方式我们就可以在URP中制作很多功能了。比如举个栗子,多Pass描边效果:

技术图片

 

 一个PASS的RenderMode为UniversalForward,另一个为TestPass,第一个Pass为了方便演示,直接Unlit,第二个Pass描边,于是有了这个效果。除了这个,这个RenderObjects的Feature还能实现很多效果,具体就由小伙伴们发挥自己的想象力啦!我们现在借助RenderObjects了解了如何使用一个Feature,那么现在我们看看这个Feature是怎么写的。因为一个Feature不能满足我们全部的需求,所以我们要学会扩展自己的Feature。

找到RenderObjects代码,如下:

[MovedFrom("UnityEngine.Experimental.Rendering.LWRP")]public class RenderObjects : ScriptableRendererFeature

我们可以看到所有的Feature都要继承ScriptableRendererFeature类。再往下我们可以看到里面定义了几个类:

[System.Serializable]
        public class RenderObjectsSettings
        {
            public string passTag = "RenderObjectsFeature";
            public RenderPassEvent Event = RenderPassEvent.AfterRenderingOpaques;

            public FilterSettings filterSettings = new FilterSettings();

            public Material overrideMaterial = null;
            public int overrideMaterialPassIndex = 0;

            public bool overrideDepthState = false;
            public CompareFunction depthCompareFunction = CompareFunction.LessEqual;
            public bool enableWrite = true;

            public StencilStateData stencilSettings = new StencilStateData();

            public CustomCameraSettings cameraSettings = new CustomCameraSettings();
        }

        [System.Serializable]
        public class FilterSettings
        {
            // TODO: expose opaque, transparent, all ranges as drop down
            public RenderQueueType RenderQueueType;
            public LayerMask LayerMask;
            public string[] PassNames;

            public FilterSettings()
            {
                RenderQueueType = RenderQueueType.Opaque;
                LayerMask = 0;
            }
        }

        [System.Serializable]
        public class CustomCameraSettings
        {
            public bool overrideCamera = false;
            public bool restoreCamera = true;
            public Vector4 offset;
            public float cameraFieldOfView = 60.0f;
        }

这些结构就是我们看到的Renderer中Feature的参数界面,也就是说Feature的参数都是在这里定义的。然后需要实现基类的两个方法:

public override void Create()
        {
            FilterSettings filter = settings.filterSettings;
            renderObjectsPass = new RenderObjectsPass(settings.passTag, settings.Event, filter.PassNames,
                filter.RenderQueueType, filter.LayerMask, settings.cameraSettings);

            renderObjectsPass.overrideMaterial = settings.overrideMaterial;
            renderObjectsPass.overrideMaterialPassIndex = settings.overrideMaterialPassIndex;

            if (settings.overrideDepthState)
                renderObjectsPass.SetDetphState(settings.enableWrite, settings.depthCompareFunction);

            if (settings.stencilSettings.overrideStencilState)
                renderObjectsPass.SetStencilState(settings.stencilSettings.stencilReference,
                    settings.stencilSettings.stencilCompareFunction, settings.stencilSettings.passOperation,
                    settings.stencilSettings.failOperation, settings.stencilSettings.zFailOperation);
        }

        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            renderer.EnqueuePass(renderObjectsPass);
        }

通过代码我们可以看到这个Feature其实就是又执行了一遍RenderObjectsPass,只不过执行时机可以自己定义。我们需要找到这两个方法在哪里调用,才能知道整个流程。

for (int i = 0; i < rendererFeatures.Count; ++i)
                    rendererFeatures[i].AddRenderPasses(this, ref renderingData);

AddRenderPass在ForwardRenderer的SetUp方法里面执行,如上代码。

 public ScriptableRenderer(ScriptableRendererData data)
        {
            foreach (var feature in data.rendererFeatures)
            {
                if (feature == null)
                    continue;

                feature.Create();
                m_RendererFeatures.Add(feature);
            }
            Clear();
        }

Create方法在ScriptableRenderer的构造函数中,如上代码。

这样,我们就可以总结出如何做自己的RenderFeature:

1.创建自己的Feature类

2.找到Feature类要执行的Pass和时机

3.如果Feature需要自定义Pass需要自己扩展URP的Pass。

扩展Feature三步走,当然,还有Feature编辑器界面,这个忽略(啊哈哈哈哈),这节主要学习了如何创建自己的Feature,具体在应用中小伙伴们要根据时机需求看是否需要扩展Feature和Pass。

博友们如果有意见或者建议,可以留言哦~

以上是关于URP学习之七--RenderFeature的主要内容,如果未能解决你的问题,请参考以下文章

URP学习之三--ForwardRenderer

大数据学习之七——MapReduce简单代码实例

python学习之第七课时--基本条件语句if

Python 学习之《Learn Python3 The Hard Way 》第七部分学习笔记

IntelliJ IDEA学习之七maven专题

Python学习之七面向对象高级编程——使用@property