虚幻4渲染编程(Shader篇)【第十八卷:Render Graph in UE4】
MY BLOG DIRECTORY:INTRODUCTION:
UnrealEngine4在最近一段时间的版本里(4.24)开始大规模使用一个叫RenderGraph的渲染框架重构整个渲染管线。不过类似BasePass这种涉及到MeshDrawCommand的部分感觉epic没有意向进行改动。如果不修改MeshDrawCommand部分的框架的前提下,我觉得这套框架比较适合屏幕空间的绘制管线,对于单个物体的绘制可能并不合适。
RenderGraph这套框架也是对底层的进一步封装,还完成了资源管理。图形部分各种资源的管理看似变得更加轻松。对于异步支持完善,能使代码功力不怎么强的TA也能轻松驾驭Unreal的底层管线(滑稽)。
RenderGraph的大体思路就是构建一个渲染表,最后调用Execute()来执行图表中的渲染逻辑,层次非常清晰。
<hr/>MAIN CONTENT:
RenderGraph可以先从RenderGraph.h这个文件开始,这里有一大片注释写了如何用它这套框架。RenderGraph主要包含两个重要组件,一个是FRDGBuilder,负责构建Render graph的资源及添加pass等,构建RenderGraph。另一个是FRDGResource,RenderGraph的资源类,所有资源都由它派生。
RenderGraph的渲染逻辑位于Pass内,要创建一个Pass使用GraphBuilder.AddPass来添加。
下面是一个使用案例:
GraphBuilder.AddPass(
RDG_EVENT_NAME(&#34;SimpleTest&#34;),
PassParameters,
ERDGPassFlags::Raster,
(FRHICommandList& RHICmdList)
{
FPixelShaderUtils::DrawFullscreenPixelShader(RHICmdList, View.ShaderMap, *PixelShader, *PassParameters, FIntRect(0, 0, TexBufferSize.X, TexBufferSize.Y));
});AddPass函数的第一个参数是这个pass事件的名字,第二个是UniformBuffer,第三个是Pass的类型,第四个是一个Lambda函数,这个函数会带有渲染逻辑,当RenderGraph调用Execute的时候,这里面的逻辑会被执行。
当一个Pass被创建的时候,必须带有一个PassParameters。PassParameters里至少要包含此次Pass的Render target。
下面我完成一个最简单的需求:用Render grap向SceneColorTexture上绘制最简单的颜色。
首先在DeferredShadingRender中添加一个调用这个Rendergraph的函数
然后再Render函数里添加上
然后在新建一个cpp文件,键入如下代码:
#include &#34;CoreMinimal.h&#34;
#include &#34;SceneRendering.h&#34;
#include &#34;RHICommandList.h&#34;
#include &#34;Shader.h&#34;
#include &#34;RHIStaticStates.h&#34;
#include &#34;ScenePrivate.h&#34;
#include &#34;RenderGraph.h&#34;
#include &#34;PixelShaderUtils.h&#34;
#include &#34;SceneTextureParameters.h&#34;
#include &#34;DeferredShadingRenderer.h&#34;
class FSimpleUseRenderGraphPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FSimpleUseRenderGraphPS);
SHADER_USE_PARAMETER_STRUCT(FSimpleUseRenderGraphPS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
}
};
IMPLEMENT_GLOBAL_SHADER(FSimpleUseRenderGraphPS, &#34;/Engine/Private/MyGS/MyRenderGraph.usf&#34;, &#34;MainPS&#34;, SF_Pixel);
void FDeferredShadingSceneRenderer::SimpleUseRenderGraph(FRHICommandListImmediate& RHICmdList)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
FRDGBuilder GraphBuilder(RHICmdList);
FIntPoint TexBufferSize = FIntPoint(SceneContext.GetSceneDepthTexture()->GetSizeX(), SceneContext.GetSceneDepthTexture()->GetSizeY());
FRDGTextureRef SceneColor = GraphBuilder.RegisterExternalTexture(SceneContext.GetSceneColor(), TEXT(&#34;SceneColor&#34;));
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
FViewInfo& View = Views;
FSceneTextureParameters SceneTextures;
SetupSceneTextureParameters(GraphBuilder, &SceneTextures);
RDG_EVENT_SCOPE(GraphBuilder, &#34;SimpleUseRenderGraph(ViewId=%d)&#34;, ViewIndex);
TShaderMapRef<FSimpleUseRenderGraphPS> PixelShader(View.ShaderMap);
FSimpleUseRenderGraphPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FSimpleUseRenderGraphPS::FParameters>();
PassParameters->RenderTargets = FRenderTargetBinding(SceneColor, ERenderTargetLoadAction::ELoad);
ClearUnusedGraphResources(*PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME(&#34;SimpleTest&#34;),
PassParameters,
ERDGPassFlags::Raster,
(FRHICommandList& RHICmdList)
{
FPixelShaderUtils::DrawFullscreenPixelShader(RHICmdList, View.ShaderMap, *PixelShader, *PassParameters, FIntRect(0, 0, TexBufferSize.X, TexBufferSize.Y));
});
}
GraphBuilder.Execute();
}
可以看到这里要做一个全屏的绘制使用RenderGraph就十分简单了,短短70行代码就搞定了,之前的文章里随便都是几百行。
然后再把shader完成即可
MyRenderGraph.usf
我这里的绘制资源都是使用引擎已经创建好的,如果想使用自己创建的Texture或者UniformBuffer需要用RenderGraphBuild创建
如果是Texture,在AddPass以后记得Extraction
<hr/>SUMMARY AND OUTLOOK:
RenderGraph其实就是一个再次封装的渲染框架,能使开发更为容易。而且epic也会用这套来重构引擎,所以搞懂这个还是很有必要的。
enjoy it.
<hr/>NEXT:
<hr/>By YivanLee 2020/1/20 也不知道啥时候吧RDG和MeshDraw融合一下 frame graph FrameGraph可能不准确,因为有些逻辑不是一帧里执行的,所以Unreal使用了RenderGraph这个术语。 是因为Frame包括但不止渲染。还有动画Graph等等[飙泪笑] 可以多pass了? 什么? 楼主有清楚void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)这个函数吗?希望讲解一下 前面的文章有 查找shader的路径真是诡异,居然跳过Shaders这一级。
页:
[1]
2