找回密码
 立即注册
查看: 839|回复: 16

Unity-SRP_02

[复制链接]
发表于 2021-12-1 13:30 | 显示全部楼层 |阅读模式
翻CoreRP文件夹的时候偶然间发现Unity也有RG系统了,so那当然是拿来high啦。文档如下。
  所以这一期就把上一期的内容移植到RG下。首先需要一个RG对象然后在SRP的构造函数里面对它进行初始化。


  然后吧我们的SRP改成partial class并新建一个DepthPass.cs。Pass_PerDepthData是当前Pass需要的Parameters,Pass_PerDepthOutput是当前Pass需要输出给下一个Pass可能用到的Parameters。RenderGraphResource是可读资源,RenderGraphMutableResource是可读可写资源,他们的生命周期都由RG管理。创建TextureRenderObjectList都是由GraphBuilder来实现。同时使用GraphBuilder.UseDepthBuffer()来绑定DepthBuffer。使用GraphBuilder.UseRendererList()来绑定RenderObject并把它们注册到该Pass的Resource。然后通过AddRenderPass()来确定该Pass需要的参数类型,且使用GraphBuilder.SetRenderFunc()来获得参数和RenderGraphContext和PassData(这两个东西便是RGExecute提交的注册的ScriptaleRenderContex和CommandBuffer以及SetRenderFunc前注册的资源参数)。然后在此函数下通过RenderGraphContext来获取前面注册的Resource和ScriptableRenderContext以及CommandBuffer,然后进行一系列CommandBuffer.Set/Draw/Dispatch即可。
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;

namespace InfinityExtend.Runtime.Rendering
{
    public partial class InfinityRenderPipeline
    {
        class Pass_PerDepthData
        {
            public RenderGraphResource RendererList;
            public RenderGraphMutableResource DepthBuffer;
        }

        struct Pass_PerDepthOutput
        {
            public RenderGraphMutableResource DepthBuffer;
        }

        Pass_PerDepthOutput RenderPass_PerDepth(Camera RenderCamera, RenderGraph RenderGraph, CullingResults CulingData)
        {
            Pass_PerDepthOutput DepthPrePassOut;
            {
                using ( RenderGraphBuilder GraphBuilder = RenderGraph.AddRenderPass<Pass_PerDepthData>("InfinityPass_PreDepth", out Pass_PerDepthData DepthPassData, CustomSamplerId.DepthBuffer.GetSampler() ) )
                {
                    TextureDesc DepthTextureDesc = new TextureDesc(Vector2.one, false, false) {
                        enableMSAA = false,
                        clearBuffer = true,
                        bindTextureMS = false,
                        name = "DepthStencilBuffer",
                        depthBufferBits = DepthBits.Depth24,
                    };
                    DepthPassData.DepthBuffer = GraphBuilder.UseDepthBuffer(RenderGraph.CreateTexture(DepthTextureDesc, InfinityShaderIDs.RT_DepthBuffer), DepthAccess.ReadWrite);
                    DepthPassData.RendererList = GraphBuilder.UseRendererList( RenderGraph.CreateRendererList(CreateOpaqueRendererListDesc(CulingData, RenderCamera, InfinityPassIDs.PreDepthPass) ) );

                    GraphBuilder.SetRenderFunc( (Pass_PerDepthData PassData, RenderGraphContext RenderContent) =>
                    {
                        DrawRendererList(RenderContent.renderContext, RenderContent.resources.GetRendererList(PassData.RendererList), RenderContent.cmd);
                    });

                    DepthPrePassOut.DepthBuffer = DepthPassData.DepthBuffer;
                }
            }
            return DepthPrePassOut;
        }
    }
}
  这里我就封成了一个DrawList因为后面Pass也可以用这个方法进行DrawRender。
public static void DrawRendererList(ScriptableRenderContext RenderContext, RendererList RendererList, CommandBuffer CommandList)
{
    if (!RendererList.isValid) {
        throw new ArgumentException("Invalid renderer list provided to DrawRendererList");
    }

    RendererList.drawSettings.enableInstancing = true;
    RendererList.drawSettings.enableDynamicBatching = true;
            
    RenderContext.ExecuteCommandBuffer(CommandList);
    CommandList.Clear();

    if (RendererList.stateBlock == null) {
        RenderContext.DrawRenderers(RendererList.cullingResult, ref RendererList.drawSettings, ref RendererList.filteringSettings);
    } else {
        var RenderStateBlock = RendererList.stateBlock.Value;
        RenderContext.DrawRenderers(RendererList.cullingResult, ref RendererList.drawSettings, ref RendererList.filteringSettings, ref RenderStateBlock);
    }
}  同样的一路套,GBufferPass基本和PreZ一样只是多了一个GraphBuilder.UseColorBuffer来注册SV_Tatget。且输入是PreZ的Out这样就可以直接读前面PreZPass的深度数据。
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;

namespace InfinityExtend.Runtime.Rendering
{
    public partial class InfinityRenderPipeline
    {
        class Pass_GBufferData
        {
            public RenderGraphResource RendererList;
            public RenderGraphMutableResource GBufferBaseColor;
            public RenderGraphMutableResource GBufferMicroface;
            public RenderGraphMutableResource GBufferWorldNormal;
            public RenderGraphMutableResource GBufferEmissive;
        }

        struct Pass_GBufferOutput
        {
            public RenderGraphMutableResource GBufferBaseColor;
            public RenderGraphMutableResource GBufferMicroface;
            public RenderGraphMutableResource GBufferWorldNormal;
            public RenderGraphMutableResource GBufferEmissive;
        }

        Pass_GBufferOutput RenderPass_ThinGBuffer(Camera RenderCamera, RenderGraph RenderGraph, CullingResults CullingData, RenderGraphMutableResource DepthBuffer)
        {
            Pass_GBufferOutput GBufferPassOut;
            {
                using (RenderGraphBuilder GraphBuilder = RenderGraph.AddRenderPass<Pass_GBufferData>("InfinityPass_GBuffer", out Pass_GBufferData GBufferData, CustomSamplerId.GBuffer.GetSampler()) )
                {
                    ///Init RenderDesc
                    TextureDesc GBufferBaseColorDesc = new TextureDesc(Vector2.one, true, true) {
                        clearBuffer = true,
                        clearColor = Color.clear,
                        name = "GBufferBaseColor",
                        colorFormat = GraphicsFormat.R8G8B8A8_UNorm,
                    };
                    TextureDesc GBufferMicrofaceDesc = new TextureDesc(Vector2.one, true, true) {
                        clearBuffer = true,
                        clearColor = Color.clear,
                        name = "GBufferMicroface",
                        colorFormat = GraphicsFormat.R8G8B8A8_UNorm,
                    };
                    TextureDesc GBufferNormalDesc = new TextureDesc(Vector2.one, true, true) {
                        clearBuffer = true,
                        clearColor = Color.clear,
                        name = "GBufferNormal",
                        colorFormat = GraphicsFormat.A2B10G10R10_UNormPack32,
                    };
                    TextureDesc GBufferEmissiveDesc = new TextureDesc(Vector2.one, true, true) {
                        clearBuffer = true,
                        clearColor = Color.clear,
                        name = "GBufferEmissive",
                        colorFormat = GraphicsFormat.R16G16B16A16_SFloat,
                    };

                    ///Set RenderTarget
                    GraphBuilder.UseDepthBuffer(DepthBuffer, DepthAccess.Read);
                    GBufferData.GBufferBaseColor = GraphBuilder.UseColorBuffer(RenderGraph.CreateTexture(GBufferBaseColorDesc, InfinityShaderIDs.RT_GBufferBaseColor), 0);
                    GBufferData.GBufferMicroface = GraphBuilder.UseColorBuffer(RenderGraph.CreateTexture(GBufferMicrofaceDesc, InfinityShaderIDs.RT_GBufferMicroface), 1);
                    GBufferData.GBufferWorldNormal = GraphBuilder.UseColorBuffer(RenderGraph.CreateTexture(GBufferNormalDesc, InfinityShaderIDs.RT_GBufferNormal), 2);
                    GBufferData.GBufferEmissive = GraphBuilder.UseColorBuffer(RenderGraph.CreateTexture(GBufferEmissiveDesc, InfinityShaderIDs.RT_GBufferEmissive), 3);
                    GBufferData.RendererList = GraphBuilder.UseRendererList( RenderGraph.CreateRendererList(CreateOpaqueRendererListDesc(CullingData, RenderCamera, InfinityPassIDs.GBufferPass)) );

                    ///Set DrawPass
                    GraphBuilder.SetRenderFunc( (Pass_GBufferData PassData, RenderGraphContext RenderContent) =>
                    {
                        DrawRendererList(RenderContent.renderContext, RenderContent.resources.GetRendererList(PassData.RendererList), RenderContent.cmd);
                    });

                    ///Get Output
                    GBufferPassOut.GBufferBaseColor = GBufferData.GBufferBaseColor;
                    GBufferPassOut.GBufferMicroface = GBufferData.GBufferMicroface;
                    GBufferPassOut.GBufferWorldNormal = GBufferData.GBufferWorldNormal;
                    GBufferPassOut.GBufferEmissive = GBufferData.GBufferEmissive;
                }
            }
            return GBufferPassOut;
        }
    }
}  最后在SRP.cs里面吧原来的RenderContext()修改一下,如下。首先就是把五个Pass的函数按顺序设置好Dependecy。然后从CommandBufferPool申请一个CommandBuffer,并使用RenderGraph.Execute()来真正执行内容,并吧CommandBuffer和ScriptableRenderContext设置给RenderGraph即可。
        private void RenderContent_RenderGraph(bool isSceneViewCam, Camera RenderCamera, CullingResults CullingData, ScriptableRenderContext RenderContext)
        {
            //////Draw RenderFeaturePass
            Pass_PerDepthOutput PreDepthPass = RenderPass_PerDepth(RenderCamera, RenderGraph, CullingData);
            Pass_GBufferOutput GBufferPass = RenderPass_ThinGBuffer(RenderCamera, RenderGraph, CullingData, PreDepthPass.DepthBuffer);

            //////Draw SkyBox
            RenderSkyBoxPass(RenderCamera, RenderGraph);

            //////Draw Gizmos on SceneView
        #if UNITY_EDITOR
            if (isSceneViewCam) {
                RenderGizmoPass(RenderCamera, GizmoSubset.PostImageEffects, RenderGraph);
            }
        #endif

            //////Bilt To Screen
            BlitRenderGraphTextureToCameraTarget(GBufferPass.GBufferBaseColor, RenderCamera.targetTexture, RenderGraph, RenderCamera);

            //////Execute RenderGraph
            RenderGraphExecuteParams RenderGraphParams = new RenderGraphExecuteParams() {
                msaaSamples = MSAASamples.None,
                renderingWidth = RenderCamera.pixelWidth,
                renderingHeight = RenderCamera.pixelHeight
            };
            CommandBuffer RenderCommandList = CommandBufferPool.Get("InfinityCommandList");
            RenderGraph.Execute(RenderContext, RenderCommandList, RenderGraphParams);
            RenderContext.ExecuteCommandBuffer(RenderCommandList);
            CommandBufferPool.Release(RenderCommandList);
        }最后 :

  感觉还是蛮好使的,得益于Unity的诡异图形封装使得RG里DrawMesh和Dispatch都很直接。和UE的RDG不大一样的就是UE是在new RDG的时候就设置了CommandList,Unity却是最后才做,为什么一样的东西用法思想能差这么多。233

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-12-1 13:35 | 显示全部楼层
DrawMesh和Dispatch难道本来不就是很直接的吗?比如在DX里Compute Shader和Shader都是提前编译好的二进制和一个Root Signature,CS要DispatchIndirect还有一个Command Signature,剩下绘制部分就是纯逻辑了,所以我觉得Unity并没有花多少精力维护封装。
发表于 2021-12-1 13:36 | 显示全部楼层
不啊,ue里面很不直接。。
发表于 2021-12-1 13:37 | 显示全部楼层
看样子一个list把整个rg跑完了,甚至不是并行的…
发表于 2021-12-1 13:47 | 显示全部楼层
其实是并行的,srp的drawRenderer之类的是并行逻辑,只是上层指令抽象层是主线程,其实上层没多少消耗
发表于 2021-12-1 13:52 | 显示全部楼层
那是UE自己的问题。。
发表于 2021-12-1 13:54 | 显示全部楼层
可是我看drawpass function的输入直接从rendercontext拿的command buffer,应该就是execute的时候绑的那个buffer吧
发表于 2021-12-1 14:01 | 显示全部楼层
Execute并不是立即执行,是推到一个更大的队列里,最后submit才给渲染线程开始跑
发表于 2021-12-1 14:04 | 显示全部楼层
并行?你说ASyncCompute?那个RG支持但是俺PC也无福消受了,233。
发表于 2021-12-1 14:13 | 显示全部楼层
不啊,我是说cmdbuffer,每个pass节点好像都用的是exe rg的时候传进去的cmd buffer,没看到多buffer execute,单buffer肯定没法多线程记录的吧
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-23 03:27 , Processed in 0.070670 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表