Shaders#
Unreal Shading language is HLSL.
.ush
: Unreal Shader Headersincluded by other USH or USF files
.usf
: Unreal Shader Formatshould be private data only
should contain shader entry points i.e custom shaders.
Write HLSL functions for your materials#
To write shader code directly, you can add a custom shader path in your project module.
// Maps ``/Gamekit`` to ``/path/to/project/Gamekit/Shaders``
void FGamekitModule::StartupModule() {
// GamekitShaders
FString ShaderDirectory = FPaths::Combine(FPaths::ProjectPluginsDir(), TEXT("<ProjectFolderName>"), TEXT("<ShaderFolder>>"));
// Make sure the mapping does not exist before adding it
if (!AllShaderSourceDirectoryMappings().Contains("/<ShaderFolderShortcut>")){
AddShaderSourceDirectoryMapping("/<ShaderFolderShortcut>", ShaderDirectory);
}
}
void FGamekitModule::ShutdownModule() {
ResetAllShaderSourceDirectoryMappings();
}
To include a Gamekit shader file simply add /<ShaderFolderShortcut>/<ShaderFile: fire>.ush
Examples#
Gaussian Blur#
SamplerState TexSampler;
//! Simple 3x3 Gaussian Kernel
float3 GaussianBlur(Texture2D Tex, float2 UV, float Distance) {
float3 newSample =
Texture2DSample(Tex, TexSampler, UV + float2(-1, 1) * Distance) * 1.f +
Texture2DSample(Tex, TexSampler, UV + float2( 0, 1) * Distance) * 2.f +
Texture2DSample(Tex, TexSampler, UV + float2( 1, 1) * Distance) * 1.f +
Texture2DSample(Tex, TexSampler, UV + float2(-1, 0) * Distance) * 2.f +
Texture2DSample(Tex, TexSampler, UV + float2( 0, 0) * Distance) * 4.f +
Texture2DSample(Tex, TexSampler, UV + float2( 1, 0) * Distance) * 2.f +
Texture2DSample(Tex, TexSampler, UV + float2(-1, -1) * Distance) * 1.f +
Texture2DSample(Tex, TexSampler, UV + float2( 0, -1) * Distance) * 2.f +
Texture2DSample(Tex, TexSampler, UV + float2( 1, -1) * Distance) * 1.f;
return newSample / 16.f;
}
Custom Shaders#
To follow this part you will need to do the steps described in the previous section.
Warning
Global Shader compile error will make the editor crash during load up
Warning
Module using global shaders needs to be configured to load during the PostConfigInit
phase.
If not the loading will crash with a criptic error message about the OS not being able to load
your library.
"Modules": [
{
"Name": "Gamekit",
"Type": "Runtime",
"LoadingPhase": "PostConfigInit",
"WhitelistPlatforms": [ "Win64" ]
}
],
class FUpscalingShader : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FUpscalingShader);
SHADER_USE_PARAMETER_STRUCT(FUpscalingShader, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_TEXTURE(Texture2D<uint>, InputTexture) // Read Only Texture
SHADER_PARAMETER_UAV(RWTexture2D<uint>, OutputTexture) // Read Write Texture
SHADER_PARAMETER(FIntPoint, Dimensions)
SHADER_PARAMETER(UINT, TimeStamp)
SHADER_PARAMETER(UINT, Multiplier)
END_SHADER_PARAMETER_STRUCT()
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static inline void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
// Preprocessor defines
OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_X"), NUM_THREADS_PER_GROUP_DIMENSION);
OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_Y"), NUM_THREADS_PER_GROUP_DIMENSION);
OutEnvironment.SetDefine(TEXT("THREADGROUPSIZE_Z"), 1);
}
};
IMPLEMENT_GLOBAL_SHADER(
FUpscalingShader, // Shader Type
"/Gamekit/Upscaling.usf", // Shader File
"MainComputeShader", // Shader Entry point
SF_Compute // Shader Kind (Vertex, Hull, Domain, Pixel, Geometry, Compute, RayGen, RayMiss, RayHitGroup, RayCallable)
);
ReserveRenderTargets(RHICmdList);
CopyInputTextureToInputTarget(RHICmdList);
FUpscalingShader::FParameters PassParameters;
PassParameters.OutputTexture = ComputeShaderOutput->GetRenderTargetItem().UAV;
PassParameters.InputTexture = ComputeShaderInput->GetRenderTargetItem().ShaderResourceTexture;
PassParameters.Dimensions = CachedParams.OriginalSize;
PassParameters.TimeStamp = CachedParams.TimeStamp;
PassParameters.Multiplier = CachedParams.Multiplier;
TShaderMapRef<FUpscalingShader> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
FComputeShaderUtils::Dispatch(
RHICmdList,
ComputeShader,
PassParameters,
FIntVector(
FMath::DivideAndRoundUp(CachedParams.OriginalSize.X, NUM_THREADS_PER_GROUP_DIMENSION),
FMath::DivideAndRoundUp(CachedParams.OriginalSize.Y, NUM_THREADS_PER_GROUP_DIMENSION),
1
)
);
CopyOutputTargetToOutputTexture(RHICmdList);
See UnrealEngine\Engine\Source\Runtime\RHI\Public\RHIDefinitions.h
for the ETextureCreateFlags
enum.
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
// Create 2D texture description for reading
FPooledRenderTargetDesc InputTargetDesc = FPooledRenderTargetDesc::Create2DDesc(
FIntPoint(TileSize, TileSize), // FIntPoint InExtent
PF_G16, // EPixelFormat InFormat
FClearValueBinding::None, // FCLearValueBinding InClearValue
TexCreate_None, // ETextureCreateFlags InFlags
TexCreate_ShaderResource, // ETextureCreateFlags InTargetableFlags
false // bool bInForceSeparateTargetAndShaderResource
// uint16 InNumMips = 1
// bool InAutowritable = true
// bool InCreateRTWriteMask = false
// bool InCreateFmask = false
);
// Get the Texture
TRefCountPtr<IPooledRenderTarget> InputTarget;
GRenderTargetPool.FindFreeElement(
RHICmdList, // FRHICommandList& RHICmdList
InputTargetDesc, // const FPooledRenderTargetDesc& InputDesc
InputTarget, // TRefCountPtr<IPooledRenderTarget>& Out
TEXT("InputTarget") // const TCHAR* InDebugName
// ERenderTargetTransience TransienceHint = ERenderTargetTransience::Transient
// bool bDeferTextureAllocation = false
);
Initialize Input Target#
// Copy your input texture to the target texture
RHICmdList.CopyTexture(
GetTextureRHI(CachedParams.OriginalTexture),
ComputeShaderInput->GetRenderTargetItem().ShaderResourceTexture,
FRHICopyTextureInfo()
);
// Create 2D texture description for writing
FPooledRenderTargetDesc OutputTargetDesc = FPooledRenderTargetDesc::Create2DDesc(
FIntPoint(NumTilesX, NumTilesY),
PF_R8G8B8A8,
FClearValueBinding::None,
TexCreate_None,
TexCreate_UAV,
false,
);
TRefCountPtr<IPooledRenderTarget> OutputTarget;
GRenderTargetPool.FindFreeElement(
RHICmdList,
OutputTargetDesc,
OutputTarget,
TEXT("OutputTarget")
);
Retrive Output#
// Copy the output target to the output texture
RHICmdList.CopyTexture(
ComputeShaderOutput->GetRenderTargetItem().ShaderResourceTexture,
GetTextureRHI(CachedParams.UpscaledTexture),
FRHICopyTextureInfo()
);
Use Custom Shaders as materials#
Shader Parameters#
Common abbreviation:
RDG: render graph
UAV: unordered access view
SRV: Shader Resource View
Parameters:
SHADER_PARAMETER_ARRAY(float, MyScalarArray, [8])
SHADER_PARAMETER_TEXTURE(Texture2D, MyTexture)
SHADER_PARAMETER_SRV(Texture2D, MySRV)
SHADER_PARAMETER_UAV(Texture2D, MyUAV)
SHADER_PARAMETER_SAMPLER(SamplerState, MySampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, MyTexture)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, MySRV)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, MyUAV)
SHADER_PARAMETER_RDG_BUFFER(Buffer<float4>, MyBuffer)
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float4>, MySRV)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<float4>, MyUAV)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FMyStruct, MemberName)
SHADER_PARAMETER_RDG_BUFFER_UPLOAD
RDG_BUFFER_ACCESS(MyBuffer)
RDG_BUFFER_ACCESS_DYNAMIC
RDG_TEXTURE_ACCESS
RDG_TEXTURE_ACCESS_DYNAMIC
Common Errors#
[2022.02.19-18.32.59:344][522]LogWindows: Windows GetLastError: The operation completed successfully. (0)
[2022.02.19-18.32.59:345][522]LogWindows: Error: === Critical error: ===
[2022.02.19-18.32.59:345][522]LogWindows: Error:
[2022.02.19-18.32.59:345][522]LogWindows: Error: Fatal error: [File:C:/opt/UnrealEngine/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp] [Line: 902]
[2022.02.19-18.32.59:345][522]LogWindows: Error: Rendering thread exception:
[2022.02.19-18.32.59:345][522]LogWindows: Error: Assertion failed: !GRDGInExecutePassScope [File:C:/opt/UnrealEngine/Engine/Source/Runtime/RenderCore/Private/RenderGraphValidation.cpp] [Line: 512]
[2022.02.19-18.32.59:345][522]LogWindows: Error: Render graph is being executed recursively. This usually means a separate FRDGBuilder instance was created inside of an executing pass.