1597570832 9546ff42afdec241e56a6431ddb3ba96b9a57877.gif

Mini tutorial for locations close to the surface

The intent of these mini-tutorials is to have an easily searchable reference for implementing some of the newer (or changed) features in Niagara.

Here's a cool thing to do with collisions in Niagara. It's a little more expensive than techniques discussed earlier, but it opens the door to some really cool possibilities.


We will be using Niagara's collision tracking logic on the CPU to find surface locations near our particle system. We can then use this information to exclude particles from spawning and determine their starting position.

Like last time, there are two ways to follow the tutorial: Either you create it yourself using the descriptions and pictures, or you copy the contents of this pastebin into a new module script and then just use my steps as an explanation of the inner workings
Here is a pastebin for the raw code of the module. You can paste this into your module editor and it will convert it to nodes.


Near the surface – has been the main pasting tool since 2002. Pastebin is a website where you can save text online for a set period of time.

Don't forget to connect the output node after copying.

Even if you don't follow the rest of the tutorial, it will only work on the CPU in this form.

Step 1.
Create a new module script and name it something cool.

Step 2.

  • Open the module.
  • Add a new float input for MaxRadius
  • Bring in Engine.Owner.Position too. This is the world location of your particle effect.
  • Add a random point in the Sphere node. This function generates a random direction.
    It comes with the engine and is used in Sphere Location so it is thoroughly tested
  • We'll want to normalize this just in case.
    (I set the values ​​to 1 so this is not necessary, but normalization doesn't cost much, and if the vector is not normalized, the code gets seriously messed up.)
  • Next, multiply that direction by MaxRadius and add Engine.Owner.Position. This will be our space end point.
  • You can drag this value straight to the next step, but I'd like to add it to a local value for readability

Step 3.

  • Drag out a new Map-Get node and add a collision query parameter.
  • Also add Engine.Owner.Position again and pull out the local trace end.
    It is possible that adding the Engine.Owner.Position node twice could have a low performance cost. I'm pulling it out of here to make our spaghetti a little more readable.
  • Go to the "Run Collision Query Sync CPU Node", this is the big one. We want our particle system position in Start and our calculated end position in End Trace.
  • This function sends between start and end and gives us some results.
  • We want our collision to be valid if the trace is returned valid and is not on a network.
  • At the moment we only save the values ​​that interest us on the card. The new valid bool, the collision position and the collision normal. You don't need the normal for this tutorial, but it's still useful.

Step 4.

  • If you want the implementation with most barebones, you can skip this step. Just connect the position of the collision world to Particles.Position and it works. However, it never hurts to have a few options when creating it.
  • Pull out the local collision-valid boolean as well as the position and normal from the last step.
  • Also add a specified intrinsic boolean input and the Particles.Position
  • Use an if node to set the position to TraceEnd to ensure that it is an appropriate value in the event of an invalid collision.
  • I also add this separate self-check in case I want to calculate all the values ​​and have something to read, but don't want to change the position of my particles when I call this module.

Step 5.

  • Add a KillInvalid Boolean input.
  • If KillInvalid is set and the collision is actually invalid, we can set DATAINSTANCE.Alive to false. This way, particles that have no surface to spawn will not be created.

And that's it.


It is useful to make this module available in the library under Location
You can use the highlights to identify the module type in the emitter stack.
And the description will be useful for your teammates or for yourself in a few months

Please let me know if there is anything you do not understand or if I made a mistake anywhere.


Please enter your comment!
Please enter your name here