Introduction
I was in the middle of creating a game and wanted to test some blurring post-processing effects. To my surprise, I didn't find any production ready postprocessing implementations of post processing blur materials.
Choosing the right approach
So, while trying to create an effect my requirements were:
- Fast iteration;
- Rapid prototyping.
三三ᕕ( ᐛ )ᕗ 三三ᕕ( ᐛ )ᕗ 三三ᕕ( ᐛ )ᕗ
This I could achieve by using Global Custom Shaders or Post-process Material. I chose the latter due to faster prototyping. Which was crucial for me. Also, it was suggested to me by _DeepSeek _and _Qwen _ LLMs which I'm using to simplify the development process.
Development
I was really confused by the Unreal's Custom Shader node. The first iterations of the code that were suggested by Qwen were not working. The blur implementation was correct, but the integration in the engine was not right. So, after several hours of trying to make it work, I quickly understood that this is the task that requires for me to do the research by myself. ᕙ( •̀ ᗜ •́ )ᕗ
I haven't dig too deep into the node still. But I got it to the extent where it covers my needs.
So let's get to the grits of it!
First I got this useful page
https://www.kodeco.com/57-unreal-engine-4-custom-shaders-tutorial
Compiling the sample
Here I found a real example that I can work upon.
It did the Guassian blur too. I loaded the project and... The material didn't compile of course ¯\(ツ)/¯. You can see the original code below.
static const int SceneTextureId = 14;
float2 TexelSize = View.ViewSizeAndInvSize.zw;
float2 UV = GetDefaultSceneTextureUV(Parameters, SceneTextureId);
float3 PixelSum = float3(0, 0, 0);
float WeightSum = 0;
for (int x = -Radius; x <= Radius; x++)
{
for (int y = -Radius; y <= Radius; y++)
{
float2 Offset = UV + float2(x, y) * TexelSize;
float3 PixelColor = SceneTextureLookup(Offset, SceneTextureId, 0).rgb;
float Weight = Calculate1DGaussian(x / Radius) * Calculate1DGaussian(y / Radius);
PixelSum += PixelColor * Weight;
WeightSum += Weight;
}
}
return PixelSum / WeightSum;
The problem was SceneTextureLookup(Offset, SceneTextureId, 0) function call. The compiler outputted that it just couldn't find this function. In the error log there also were the link to the shader which was used while compiling the material. You can get this debug info if you turn on shader developer mode in engine settings.
So I went to that generated shader file and inspected it.
// line 3512 "/Engine/Generated/Material.ush"
float4 SceneTextureLookup(FMaterialPixelParameters Parameters, float2 UV, int SceneTextureIndex, bool bFiltered)
{
...
}
So the number of parameters are different. The new function version had new FMaterialPixelParameters argument. So I decided to dig a little bit further and found that the function was indeed changed and the current implementation
@@ \Engine\Shaders\Private\MaterialTemplate.ush 3408
// SceneTextureLookup function used by new translator. Shading path agnostic, and handles conditional application of exposure scale, so generated code doesn't need to vary.
float4 SceneTextureLookup(FMaterialPixelParameters Parameters, float2 UV, int SceneTextureIndex, bool bFiltered)
{
...
}
So currently there is a new translator that uses new signature for the function. Good, one problem solved ദ്ദി(• ˕ •マ.ᐟ
Correct SceneTextureLookup usage
The material did compile, but the material output was black. So there must be another problem (╥‸╥). And there was. The original material uses SceneTexture with World Normal
And after experimenting for a bit I got the solution. So the World Normal parameter should be changed to PostProcessInput0. The reason is.. I didn't dig that deep. But if you use Normal for SceneTexture you can't use SceneTextureLookup() function for querying only for World Normal Texture. So After the change you can query for PostProcessInput0 Texture.
Volia! ٩(^ᗜ^ )و ´-٩(^ᗜ^ )و ´-٩(^ᗜ^ )و ´- The blur works as intended
A little afterword
After that there some questions for me that I didn't dig deep enough to find answers, but have an intuational guess.
Does external shader have shader optimisations, like Global shaders, if used in Custom node? Probably not, because the the code is just copied to the generated material shader, so there is no optimisation. But I invite readers to research this deeper.
Also why I can lookup textures in custom node only that are inputs to that custon node? To me it seems like before you could lookup for any TextureId, but now, for optimization, only for specific, that were inputed.




Top comments (0)