• Unity6 URP17使用初探


    1.简介

    随着Unity6的发布,URP17也已经可以上手使用,相对旧的版本改动较大的是加入了

    RenderGraph、STP、Foveated rendering、GPU Resident Drawer等功能,部分功能只需要开关参数即可使用,

    而GRD更像是Gpu driven管线下的SRP Batches升级,RenderGraph相较于HDRP之前使用的版本换了一套API。

    最大的不同是,使用URP17编写Feature时,必须依赖于RenderGraph进行编写,接下来就来介绍一下。

     

    1.1 相关Demo

    目前URP17比较容易找到的学习Demo如下:

    2.RenderGraph

    打开任意URP的示例场景查看,RenderGraphView上各图标含义如下:

    1. 说明这是一个外部置入的RenderTexture
    2. 红色方块说明存在写入操作
    3. 绿色方块指存在读取操作(红绿方块说明读写操作)
    4. 该图标说明标记了全局RenderTexture

     而顶部表明当前渲染一帧的各个Pass,左侧是各类RT。

     

    URP17同时保留了旧的Feature逻辑与RenderGraph逻辑(打开任意pass文件为例):

    复制代码
    public class DistortTunnelPass_Tunnel : ScriptableRenderPass
    {
        class PassData
        {
            public Renderer tunnelObject;
            public Material tunnelMaterial;
        }
    
    
    #pragma warning disable 618, 672 // Type or member is obsolete, Member overrides obsolete member
    
        // Unity calls the Configure method in the Compatibility mode (non-RenderGraph path)
        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescripor)
        {
        }
    
        // Unity calls the Execute method in the Compatibility mode
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
        }
    
    #pragma warning restore 618, 672
    
        // Unity calls the RecordRenderGraph method to add and configure one or more render passes in the render graph system.
        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
        {
        }
    }
    复制代码

    参考时忽略掉Configure和Execute的逻辑,执行逻辑关注RecordRenderGraph函数。

     

    2.1 操作方式的改变

    在RenderGraph中,之前的RTHandle由于不在该系统中托管,进入RenderGraph的材质都需要调用API进行转换,

    转换为RendeGraph的RT后,无需考虑释放操作:

    RenderTextureDescriptor textureProperties = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
    TextureHandle textureHandle = UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "My texture", false);

    相关文档:

    https://docs.unity3d.com/Manual/urp/render-graph-create-a-texture.html

     

    此外RenderGraph对于空调用的pass,也会剔除进行优化,使用者需要手动标记以防止被剔除。

     

    2.1 RecordRenderGraph

    在该函数内可组织渲染逻辑,pass相关的逻辑需放在对应的代码块中,例如:

    复制代码
    using (var builder = renderGraph.AddRasterRenderPass(passName, out _))
    {
        builder.UseTexture(rt1);
        builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
    
        builder.SetRenderFunc((data, context) =>
        {
            MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
            materialPropertyBlock.SetTexture("_BlitTexture", rt1);
            materialPropertyBlock.SetVector("_BlitScaleBias", new Vector4(1, 1, 0, 0));
    
            context.cmd.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Triangles, 3, 1, materialPropertyBlock);
        });
    }
    复制代码

    URP提供了多种RenderPass,例如处理光栅化相关逻辑使用RasterRenderPass组织相关逻辑。

    在RenderPass的代码块中可使用builder对象配置RenderTarget、标记材质的读写等

    而具体的pass绘制逻辑则在SetRenderFunc代码块中。

     

    RecordRenderGraph内可以调用多次AddRenderPass,但URP并没有整理旧API的代码和相关工具类,

    以至于容易使用旧的API导致报错,这点需要注意。

     

    3.编写Feature

    3.1 Blit与SetTarget

    从前有句俗话“切RT的性能消耗相当于半个pass”,Unity SRP在几个版本的升级都在逐渐强调不切RenderTarget直接绘制,

    如Cockpit Demo的屏幕空间描边。

     

    3.2 屏幕模糊Demo

    下面通过屏幕模糊Demo案例,演示URP17下pass的编写。

     

    通过外部EnqueuePass的方式,在场景中通过控制器脚本添加该Pass,

    MyBlurSceneController.cs:

    复制代码
    using UnityEngine;
    using UnityEngine.Rendering.Universal;
    using UnityEngine.Rendering;
    
    public class MyBlurSceneController : MonoBehaviour
    {
        public Material material;
        [Range(2, 15)] public int blurPasses = 3;
        [Range(0, 4)] public int downSample = 0;
        [Range(0.0f, 10f)] public float offset = 0.2f;
    
        public RenderPassEvent injectionPoint = RenderPassEvent.BeforeRenderingPostProcessing;
        public int injectionPointOffset = 0;
        public ScriptableRenderPassInput inputRequirements = ScriptableRenderPassInput.Color;
        public CameraType cameraType = CameraType.Game;
    
        private MyBlurPass mMyBlurPass;
    
    
        private void OnEnable()
        {
            SetupPass();
    
            RenderPipelineManager.beginCameraRendering += OnBeginCamera;
        }
    
        private void OnDisable()
        {
            RenderPipelineManager.beginCameraRendering -= OnBeginCamera;
        }
    
        public virtual void SetupPass()
        {
            mMyBlurPass = new MyBlurPass();
    
            mMyBlurPass.renderPassEvent = injectionPoint + injectionPointOffset;
            mMyBlurPass.material = material;
    
            mMyBlurPass.ConfigureInput(inputRequirements);
        }
    
        public virtual void OnBeginCamera(ScriptableRenderContext ctx, Camera cam)
        {
            if (mMyBlurPass == null || material == null)
                return;
    
            if ((cam.cameraType & cameraType) == 0) return;
    
            mMyBlurPass.blurPasses = blurPasses;
            mMyBlurPass.downSample = downSample;
            mMyBlurPass.offset = offset;
    
            cam.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(mMyBlurPass);
        }
    }
    复制代码

     

    MyBlurPass.cs:

    复制代码
    using UnityEngine;
    using UnityEngine.Rendering.RenderGraphModule;
    using UnityEngine.Rendering;
    using UnityEngine.Rendering.Universal;
    using UnityEngine.Rendering.RenderGraphModule.Util;
    
    public class MyBlurPass : ScriptableRenderPass
    {
        public class PassData
        {
            public TextureHandle tempRt1;
            public TextureHandle tempRt2;
        }
    
        public Material material;
        [Range(2, 15)] public int blurPasses = 3;
        [Range(1, 4)] public int downSample = 1;
        [Range(0.0f, 10f)] public float offset = 0.2f;
    
    
        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
        {
            var resourceData = frameData.Get();
            var passData = new PassData();
    
            var w = Screen.width >> downSample;
            var h = Screen.height >> downSample;
    
            RenderTextureDescriptor textureProperties = new RenderTextureDescriptor(w, h, RenderTextureFormat.Default, 0);
            passData.tempRt1 = UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "MyBlurPassTempRt1", false);
    
            textureProperties = new RenderTextureDescriptor(w, h, RenderTextureFormat.Default, 0);
            passData.tempRt2 = UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "MyBlurPassTempRt2", false);
    
            var rt1 = passData.tempRt1;
            var rt2 = passData.tempRt2;
    
            //将屏幕RT Blit到rt1上
            var para = new RenderGraphUtils.BlitMaterialParameters(resourceData.activeColorTexture, rt1, material, 0);
            renderGraph.AddBlitPass(para, "MyBlurPassBlitFirst");
    
            material.SetFloat("_SampleOffset", offset);
    
            //模糊迭代
            for (int i = 0; i < blurPasses - 1; ++i)
            {
                para = new RenderGraphUtils.BlitMaterialParameters(rt1, rt2, material, 0);
                renderGraph.AddBlitPass(para, $"MyBlurPassBlit_{i}");
    
                var tmp = rt1;
                rt1 = rt2;
                rt2 = tmp;
            }
    
            //通过直接绘制的方式,将模糊RT绘制到屏幕上
            using (var builder = renderGraph.AddRasterRenderPass(passName, out _))
            {
                builder.UseTexture(rt1);
                builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
    
                builder.SetRenderFunc((data, context) =>
                {
                    MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
                    materialPropertyBlock.SetTexture("_BlitTexture", rt1);
                    materialPropertyBlock.SetVector("_BlitScaleBias", new Vector4(1, 1, 0, 0));
    
                    context.cmd.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Triangles, 3, 1, materialPropertyBlock);
                });
            }
        }
    }
    复制代码

     

    接着在ShaderGraph中连出模糊的逻辑,注意Blit对应的参数_BlitTexture、_BlitScaleBias:

     

    最后在场景中挂载控制器以及材质球,即可使用该模糊Pass。

     

  • 相关阅读:
    【Flask 系统教程 7】数据库使用 SQLAlchemy
    【面试】class文件里面是什么?
    你不知道的Python容器
    Seata部署TC服务实现高可用和异地容灾
    【vue2第十五章】VueRouter 路由配置(VueRouter)与使用 和 router-link与router-view标签使用
    Git学习
    MySQL之库操作
    VS编译.cu文件源文件无法打开matrix.h和mex.h问题
    DB2HADR 一主多备 环境搭建 centos7搭建db2 hadr 一主多备
    Nginx学习与实战 · 解决net::ERR_CONTENT_LENGTH_MISMATCH 206问题
  • 原文地址:https://www.cnblogs.com/hont/p/18515153