[Niagara 4.25] Particle Decals Mini Tutorial

Both deffered decals and these material decals are unable to render on transparent materials.

  1. These decals are rendered during the seperate translucency pass (same as transparent materials) so there is no way to guarantee the nececary data is available for blending.
  2. Transparent/Additive materials do not write their depth to a buffer, and as such it impossible to reconstruct their worldspace positions.

It might be possible to hack this in very specific situations. Using render targets, you can render a seperate depth buffer in which these objects only render their depth. Then in the decal material, you would use only the smalles depth between pixel depth and this depth buffer.

It’s funny to me no one posted the result of what you said. Derivatives of WPBT function look pretty cool when fed into Tobasco’s idea. I wish I could mix it with some kind of self shadowing. I like the effect on high detail / displacment-ed geometry. Although, I wonder if we get the same effect using just a spotlight.

1 Like

Is it possible to change the axis from which to blend, currently its the up, or Z axis. Is it possible to rotate the object and have it project the texture on a vertical surface, and not to have stretching on a horizontal one?

You can fade to any arbitrary axis with dot(vertexNormal, [axis]) where axis is a vector3

How would I then alter the UVs for the texture, since they do the projecting of the texture

I just rotated the particle here

The uv’s automatically rotate with the particle if you set TransformVector to MeshParticleSpace to WorldSpace.

To fade in the same direction, apply this same TransformVector to Vector3(0,0,1), then dot the worldnormal against that transformed vector.

1 Like

first of all thanks for this amazing tutorial .
i might be a bit late but do you know how to exclude certain meshes from being projeced ?
ty in advance

You’ll need a screenspace buffer (depth/presorted stencil) to check against.
with presorted, I mean a stencil that only draws if it is not obstructed by the z-buffer

In personal projects I usually use the custom depth buffer.
If it is not a personal project, now is the time to go and talk to your friendly neigbourhood graphics programmer and explain the situation. They’ll be able to help you out.

Once you have that.

  • In case of stencil, just use the stencil as a mask (multiply before feeding into opacity)
  • In case of depth buffer, use saturate(sceneDepth- depthBuffer) to only show where the projected pixels would be in front of the recorded depth buffer. (otherwise if the selected object is obscured, it will still be able to mask out pixels)

This is really an awesome guide. Can you cover me on this node tho “WorldPositionBehindTranslucency”? I kinda understand the later part but what does this node do?

You can double click the node to see the implementation.

I’ll try to explain for future reference:


  • Scene Depth is the depth recorded in the depth buffer (translucency doesn’t write into depth, so we can be certain this is the closest opaque object)
  • Pixel Depth is the depth of the current pixel

Dividing SceneDepth by pixeldepth, or essentially, what part of the total scenedepth is our current pixeldepth


  • Absolute world position is the current pixel in world space.
  • CamerPosition is the camera position in world space.

Subtracting Camera position from the world position gives us a vector pointing from the camera to the pixel we currently deal with (fragment technically I believe, but it’s ok to think about it as pixels)

First we multiply our vector from the camera to the pixel position with the scene depth fraction, so now we have a vector which points from the camera in the direction of the current pixel, but with the length of the scene depth.

So now the only thing we need to get a worldspace vector is to add our camera position back into the vector.

To visualize the depth situation, it can be useful to think in numbers.
Current scenedepth is 10m
Current pixeldepth is 5m ( it’s always smaller, if it were bigger the pixel would be behind the depth end therefore not get rendered)

Fraction = 10/5, or we need to make the vector 2 times as large to reach the current scene depth.

I hope that clears it up :smiley:


Yes. First, thanks for spending your time explaining things to me. Tbh it was still confusing me at first and I had to spend all day to research scene depth and pixel depth since I rarely use both when I make material. But now, it’s getting more and more clear to me, I’m very grateful and thank you for sharing your knowledge to our community. I started learning VFX by myself so it’s really difficult.
Hope you have a nice day!

1 Like

First of all thanks for sharing this its so useful.
Is there so form to implement normals?. I tried it but it doesnt work.

Can you be a bit more specific? whic part did you try and didn’t work? Also can you show your setup?

Maybe this is a mistake but I just activated Default lit and activate Volumetric directional for having normals.

1 Like

I don’t really understand what you are tying to do.

If you want the fade the decal based on the normal of the background, have a look at the post from Shannon Berke (Reply 10)
There is a good explanation of how to use the world normal scenetexture to your advantage!

1 Like

Very nice tutorial, gonna try this with niagara collision, I wonder if this would work to spawn niagara decal on particle colision :grin:

1 Like

It absolutely does, just set the position and the trace position and rotate it to the normal and you should be good!

1 Like

ue decal colision

Work super well with collision, there is some artifact if multiple decal is spawned at same position.

Is there any ways to kill particle on first collision inside niagara ?
Is there an option to disable homegrid as deflector? ( Just wonder what if I have object that below homegrid) :smiley:

I believe it’s not part of the module, but you can set aging on collision, so if you set a really large number there, it looks the same as killing on hit.

What is homegrid? You can set a tracing channel and then remove that object from that channel to stop colliding with it.

1 Like

Sorry what I mean homegrid is basically a default grid, as you can see here, the particle collision is hiting the grid instead hitting the box below collision