zoukankan      html  css  js  c++  java
  • 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。

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

  • 相关阅读:
    C++ 把输出结果写入文件/从文件中读取数据
    转载:C++之高精度算法
    借助bool判断使冒泡排序效率提高
    启程
    2017总结,2018的路
    mysql 分组排序
    2021年VS2019最新有效的调试ASP.NET Core源码
    神级Java程序员 开车教你基础开发,最简单 微型Java Web框架
    手把手教你 基础 整合最优雅SSM框架:SpringMVC + Spring
    学习Java绝对要懂的,Java编程中最常用的几种排序算法!
  • 原文地址:https://www.cnblogs.com/shenyibo/p/12554211.html
Copyright © 2011-2022 走看看