Unity-SRP_02
翻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管理。创建Texture和RenderObjectList都是由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>(&#34;InfinityPass_PreDepth&#34;, out Pass_PerDepthData DepthPassData, CustomSamplerId.DepthBuffer.GetSampler() ) )
{
TextureDesc DepthTextureDesc = new TextureDesc(Vector2.one, false, false) {
enableMSAA = false,
clearBuffer = true,
bindTextureMS = false,
name = &#34;DepthStencilBuffer&#34;,
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(&#34;Invalid renderer list provided to DrawRendererList&#34;);
}
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>(&#34;InfinityPass_GBuffer&#34;, out Pass_GBufferData GBufferData, CustomSamplerId.GBuffer.GetSampler()) )
{
///Init RenderDesc
TextureDesc GBufferBaseColorDesc = new TextureDesc(Vector2.one, true, true) {
clearBuffer = true,
clearColor = Color.clear,
name = &#34;GBufferBaseColor&#34;,
colorFormat = GraphicsFormat.R8G8B8A8_UNorm,
};
TextureDesc GBufferMicrofaceDesc = new TextureDesc(Vector2.one, true, true) {
clearBuffer = true,
clearColor = Color.clear,
name = &#34;GBufferMicroface&#34;,
colorFormat = GraphicsFormat.R8G8B8A8_UNorm,
};
TextureDesc GBufferNormalDesc = new TextureDesc(Vector2.one, true, true) {
clearBuffer = true,
clearColor = Color.clear,
name = &#34;GBufferNormal&#34;,
colorFormat = GraphicsFormat.A2B10G10R10_UNormPack32,
};
TextureDesc GBufferEmissiveDesc = new TextureDesc(Vector2.one, true, true) {
clearBuffer = true,
clearColor = Color.clear,
name = &#34;GBufferEmissive&#34;,
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(&#34;InfinityCommandList&#34;);
RenderGraph.Execute(RenderContext, RenderCommandList, RenderGraphParams);
RenderContext.ExecuteCommandBuffer(RenderCommandList);
CommandBufferPool.Release(RenderCommandList);
}最后 :
感觉还是蛮好使的,得益于Unity的诡异图形封装使得RG里DrawMesh和Dispatch都很直接。和UE的RDG不大一样的就是UE是在new RDG的时候就设置了CommandList,Unity却是最后才做,为什么一样的东西用法思想能差这么多。233 DrawMesh和Dispatch难道本来不就是很直接的吗?比如在DX里Compute Shader和Shader都是提前编译好的二进制和一个Root Signature,CS要DispatchIndirect还有一个Command Signature,剩下绘制部分就是纯逻辑了,所以我觉得Unity并没有花多少精力维护封装。 不啊,ue里面很不直接。。 看样子一个list把整个rg跑完了,甚至不是并行的… 其实是并行的,srp的drawRenderer之类的是并行逻辑,只是上层指令抽象层是主线程,其实上层没多少消耗 那是UE自己的问题。。 可是我看drawpass function的输入直接从rendercontext拿的command buffer,应该就是execute的时候绑的那个buffer吧 Execute并不是立即执行,是推到一个更大的队列里,最后submit才给渲染线程开始跑 并行?你说ASyncCompute?那个RG支持但是俺PC也无福消受了,233。 不啊,我是说cmdbuffer,每个pass节点好像都用的是exe rg的时候传进去的cmd buffer,没看到多buffer execute,单buffer肯定没法多线程记录的吧
页:
[1]
2