Download

Customizing global shader doesn't work. (UE4.26)

Hi there, I’ve tried to add a global shader and use it.
I know the official documents are out of date for a long time so I’ve also modified the codes as following:

First, it’s a Render function in deferred shading scene renderer.
It’s called before RenderFinish() in DeferredShadingRenderer.cpp

void FDeferredShadingSceneRenderer::RenderSceneInverse(FRHICommandList& RHICmdList)
{
	// Get the collection of Global Shaders
	auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
	
	// Get the actual shader instances off the ShaderMap
	TShaderMapRef<FSceneInverseVS> SceneInverseVS(ShaderMap);
	TShaderMapRef<FSceneInversePS> SceneInversePS(ShaderMap);
	
	// Declare a bound shader state using those shaders and apply it to the command list
	FGraphicsPipelineStateInitializer GraphicsPSOInitializer;
	RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInitializer);
	GraphicsPSOInitializer.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
	GraphicsPSOInitializer.BlendState = TStaticBlendState<>::GetRHI();
	GraphicsPSOInitializer.RasterizerState = TStaticRasterizerState<>::GetRHI();
	GraphicsPSOInitializer.PrimitiveType = PT_TriangleStrip;
	GraphicsPSOInitializer.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
	GraphicsPSOInitializer.BoundShaderState.VertexShaderRHI = SceneInverseVS.GetVertexShader();
	GraphicsPSOInitializer.BoundShaderState.PixelShaderRHI = SceneInversePS.GetPixelShader();
	SetGraphicsPipelineState(RHICmdList, GraphicsPSOInitializer);

	// create vertex buffer
	FRHIResourceCreateInfo CreateInfo;
	FVertexBufferRHIRef VertexBufferRHI = RHICreateVertexBuffer(sizeof(FFilterVertex) * 4, BUF_Volatile, CreateInfo);
	void* VoidPtr = RHILockVertexBuffer(VertexBufferRHI, 0, sizeof(FFilterVertex) * 4, RLM_WriteOnly);

	FFilterVertex* Vertices = (FFilterVertex*)VoidPtr;
	Vertices[0].Position = FVector4(-1.0f, 1.0f, 0, 1.0f);
	Vertices[1].Position = FVector4(1.0f, 1.0f, 0, 1.0f);
	Vertices[2].Position = FVector4(-1.0f, -1.0f, 0, 1.0f);
	Vertices[3].Position = FVector4(1.0f, -1.0f, 0, 1.0f);
	Vertices[0].UV = FVector2D(0, 0);
	Vertices[1].UV = FVector2D(1, 0);
	Vertices[2].UV = FVector2D(0, 1);
	Vertices[3].UV = FVector2D(1, 1);
	RHIUnlockVertexBuffer(VertexBufferRHI);

	RHICmdList.SetStreamSource(0, VertexBufferRHI, 0);
	RHICmdList.DrawPrimitive(0, 2, 1);
}

As we can see, pipeline and shader should be set properly.
The shader code and shader class are shown as below:

#include "/Engine/Public/Platform.ush"

// Simple pass-through vertex shader

void MainVS(
	in float4 InPosition : ATTRIBUTE0,
	out float4 Output : SV_POSITION
)
{
	Output = InPosition;
}

// Simple solid color pixel shader
float4 MainPS() : SV_Target0
{
	return float4(1,1,0,1);
}

Just a simple yellow output shader.

In header:

#pragma once
#include "GlobalShader.h"

class FSceneInverseVS : public FGlobalShader
{
public:
	DECLARE_EXPORTED_SHADER_TYPE(FSceneInverseVS, Global, /*MYMODULE_API*/);

	FSceneInverseVS() { }
	FSceneInverseVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
	}

	static bool ShouldCache(EShaderPlatform Platform)
	{
		return true;
	}
	
};

class FSceneInversePS : public FGlobalShader
{
	DECLARE_EXPORTED_SHADER_TYPE(FSceneInversePS, Global, /*MYMODULE_API*/);

	FSceneInversePS() { }
	FSceneInversePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
	}

	static bool ShouldCache(EShaderPlatform Platform)
	{
		// Could skip compiling for Platform == SP_METAL for example
		return true;
	}

};

And in cpp:

#include "SceneInverse.h"

IMPLEMENT_SHADER_TYPE(, FSceneInverseVS, TEXT("/Engine/SceneInverse.usf"), TEXT("MainVS"), SF_Vertex);
IMPLEMENT_SHADER_TYPE(, FSceneInversePS, TEXT("/Engine/SceneInverse.usf"), TEXT("MainPS"), SF_Pixel);

Am I missing anything here?
Thanks!

Okay, after debugging with RenderDoc.
I’ve realized I didn’t set a render target for this.
It seems we don’t use OMSetRenderTarget directly in UE.
But define a render target slot in shader parameters instead?