Gaussian blur post processing material

Same problem here. If I add more offsets and make the loop >5 it says “infinite loop”.

This is nice and very useful but I noticed the scenetexture input doesn’t actually do anything. I was trying to plug in a mask and blur that. Anyone know how to get that working again?

Same issue here, did you solve it?

since all searches seem to lead to this thread and it didnt have a solution yet…there you go:


float3 res = 0;

//new - get invSize from here
float2 invSize = View.ViewSizeAndInvSize.zw;

//new - we need to fix uv coordinates like this (still seems to be a bug in 4.21)
uv = ViewportUVToSceneTextureUV(uv,14);

int TexIndex = 14;
float weights] =
{
  0.01, 0.02, 0.04, 0.02, 0.01,
  0.02, 0.04, 0.08, 0.04, 0.02,
  0.04, 0.08, 0.16, 0.08, 0.04,
  0.02, 0.04, 0.08, 0.04, 0.02,
  0.01, 0.02, 0.04, 0.02, 0.01
};

float offsets] = { -4, -2, 0, 4, 2 };

if(Mask <= 0.01) return SceneTextureLookup(uv, TexIndex, false);

uv *= 0.5;
for (int i = 0; i < 5; ++i)
{
  float v = uv.y + offsets* * invSize.y * Mask * BlurStrength;
  int temp = i * 5;
  for (int j = 0; j < 5; ++j)
  {
    float u = uv.x + offsets[j] * invSize.x * Mask * BlurStrength;
    float2 uvShifted = uv + float2(u, v);
    float weight = weights[temp + j];
    float3 tex = SceneTextureLookup(uvShifted, TexIndex, false);
    res += tex * weight;
  }
}

return float4(res, 1);

add two more inputs:
**Mask **- a 0-1 value that can mask pixels from the blur (i needed to only blur pixels close the the camera, hence the scenedepth node; play around with the 0.005 multiplier to modify the distance; its kinda a cheap depth of field effect…)
**BlurStrength **- guess what :slight_smile: dont overdo it though, its not increasing the sample count, only the ‘offset’ of the blurred pixel

have fun!

5 Likes

Hi, thx very much for this post process blur. !!
i use it to replace the old gaussian blur epic just removed out of the engine …
is there a way to improve the quality of the blur. ?
kind regards
stucki

is it possible to do this with material texture param instead of texture object or scene texture?

Does anybody have the latest version, getting errors when trying to implement this.

Pasting the code into the forum removes a few bracket-char’s, I’ve copied the code I am using as well as a picture. Make sure you update anything WRT the arrays, the [ and ] chars.

-=-=-=-
float3 res = 0;

//new - get invSize from here
float2 invSize = View.ViewSizeAndInvSize.zw;

//new - we need to fix uv coordinates like this (still seems to be a bug in 4.21)
uv = ViewportUVToSceneTextureUV(uv,14);

int TexIndex = 14;
float weights[] = { 0.01, 0.02, 0.04, 0.02, 0.01, 0.02, 0.04, 0.08, 0.04, 0.02, 0.04, 0.08, 0.16, 0.08, 0.04, 0.02, 0.04, 0.08, 0.04, 0.02, 0.01, 0.02, 0.04, 0.02, 0.01};

float offsets[] = { -4, -2, 0, 4, 2 };

if(Mask <= 0.01) return SceneTextureLookup(uv, TexIndex, false);

uv *= 0.5;
for (int i = 0; i < 5; ++i)
{
float v = uv.y + offsets[i] * invSize.y * Mask * BlurStrength;
int temp = i * 5;
for (int j = 0; j < 5; ++j)
{
float u = uv.x + offsets[j] * invSize.x * Mask * BlurStrength;
float2 uvShifted = uv + float2(u, v);
float weight = weights[temp + j];
float3 tex = SceneTextureLookup(uvShifted, TexIndex, false);
res += tex * weight;
}
}

return float4(res, 1);

-=-=-=-

Month later and this has been really helpful. Is there anyway to tweak the quality of the blur? new to shader development but I got it working, thank you so much

The offsets and weights arrays will control the sizing of the blur as well as the strength. Offsets control how far away/off the current pixel you are sampling, and the strength is how strong (lol) the effect is.

There is also a blur-strength variable that will show up as an input in the material graph. The arrays will control the overall spacing/impact of the effect, but these are ultimately multiplied by BlurStrength near the bottom of the code.

Somehow this filter makes the image brighter (Even if I set blur strength to 0):

pre-blur:
image

blurred:
image

Any suggestions? :frowning:

1 Like

heyy I’m uncertain why some sort of brightness gets added but after using it myself and experiencing the same problem, dividing the output by 2 or multiplying by 0.5 restores the original brightness.

I’m really curious if people still use this code.

Below is the code I use in UE4.27 and thankfully it works, thanks so much guys!

UPDATE: A different setup I found that works better in my case (Made by Marvelmaster)
This version is made as material function and makes it possible to use a texture instead!
Notes,

  • Switching the texture sample outputs in the function to RGB/RGBA creates a blur in color.
  • Exposing the 0.001 variable lets you increase/decrease the blur strenght.
    (to not work in decimals I recommend changing the value to 1 and dividing by 1000))
float3 res = 0;

//new - get invSize from here
float2 invSize = View.ViewSizeAndInvSize.zw;

//new - we need to fix uv coordinates like this (still seems to be a bug in 4.21)
uv = ViewportUVToSceneTextureUV(uv,14);

int TexIndex = 14;
float weights[] = { 0.01, 0.02, 0.04, 0.02, 0.01, 0.02, 0.04, 0.08, 0.04, 0.02, 0.04, 0.08, 0.16, 0.08, 0.04, 0.02, 0.04, 0.08, 0.04, 0.02, 0.01, 0.02, 0.04, 0.02, 0.01};

float offsets[] = { -4, -2, 0, 4, 2 };

if(Mask <= 0.01) return SceneTextureLookup(uv, TexIndex, false);

uv *= 0.5;
for (int i = 0; i < 5; ++i)
{
float v = uv.y + offsets[i] * invSize.y * Mask * BlurStrength;
int temp = i * 5;
for (int j = 0; j < 5; ++j)
{
float u = uv.x + offsets[j] * invSize.x * Mask * BlurStrength;
float2 uvShifted = uv + float2(u, v);
float weight = weights[temp + j];
float3 tex = SceneTextureLookup(uvShifted, TexIndex, false);
res += tex * weight;
}
}

return float4(res, 1);


1 Like

How to use them?I don’t know where is the code

The code is in the above posts. Scroll up and you should see screenshots of the setup using a Custom node.

This Effect is not Gaussian Blur I see at Photoshop.

Hello, I stumbled across this and saw the HLSL was riddled with errors so I’ve corrected them and provided the working version below. Please note I did rename some inputs, so you’ll need to adjust.

You may want to use a ping/pong strategy (2 render textures) if you want a very wide blur, or check out Ben Cloward’s channel on YT for post effect blurs.

invSize is the inverse size of your texture. You should get this from the texture itself but as I said, I’m just quickly correcting things.

Calculate inverse size with 1/texture size, for example: 1/2048

float3 res = 0;
float2 invSize = float2(0.000488, 0.000488);

float weights[] =
{
  0.01, 0.02, 0.04, 0.02, 0.01,
  0.02, 0.04, 0.08, 0.04, 0.02,
  0.04, 0.08, 0.16, 0.08, 0.04,
  0.02, 0.04, 0.08, 0.04, 0.02,
  0.01, 0.02, 0.04, 0.02, 0.01
};

float offsets[] = { -2, -1, 0, 1, 2 };

uv *= 0.5;

for (int i = 0; i < 5; ++i)
{
  float v = uv.y + offsets[i] * invSize.y;

  int temp = i * 5;
  for (int j = 0; j < 5; ++j)
  {

    float u = uv.x + offsets[j] * invSize.x;
    float2 uvShifted = uv + float2(u, v);
    float weight = weights[temp + j];

    float3 rgb = Texture2DSample(tex, texSampler, uvShifted).rgb;
    res += rgb * weight;

  }

}

return float4(res, 1);

And finally, I wasn’t using a post process (I am preparing offline textures) so you’ll need to feed in the texture and deal with the output. A good learning exercise for some.

Code from @Ollinator helped me to write my first custom node in a material blueprint - thank you!

The code below works (for me) in UE5.4.4. It has variable kernel size and variable (exponential - not gaussian) blur strength.

Maybe the next noob in line will find this useful :slight_smile:

Custom node code:

int sizeInt = size;

// Identify PostProcessInput0
int TexIndex = 14;

// Convert UV coordinates
uv = ViewportUVToSceneTextureUV(uv, TexIndex);

// SceneTexture size
float2 invSize = View.ViewSizeAndInvSize.zw;

float3 res = 0.0;
float weightSum = 0.0;

float iWeight = 0.5;
for (int i = 0; i < sizeInt; ++i)
{
  float iOffset = i + 0.5 - sizeInt / 2.0;
  float vOffset = uv.y + iOffset * invSize.y;
  iWeight *= i*2 <= sizeInt ? base : 1.0/base;

  float jWeight = 0.5;
  for (int j = 0; j < sizeInt; ++j)
  {
    float jOffset = (j + 0.5 - sizeInt / 2.0);
    float2 uvOffset = float2(uv.x + jOffset * invSize.x, vOffset);
    jWeight *= j*2 <= sizeInt ? base : 1.0/base;

    float weight = iWeight * jWeight;
    // Implicitly uses SceneTexture input!
    float3 rgb = SceneTextureLookup(uvOffset, TexIndex, false);

    res += rgb * weight;
    weightSum += weight;
  }
}
res /= weightSum;

return float4(res, 1);

Inputs:

  • uv (from TexCoord)
  • SceneTexture (from SceneTexture with PostProcesInput0 selected)
  • size = 5.0 to match behavior above
  • base = 2.0 to match behavior above