Near Surface Location Mini Tutorial
The intention of these mini tutorials is to have easily searchable reference for implementations of some of the newer (or altered) features in Niagara.
Here’s a cool thing you can do with collisions in Niagara. It is slightly more expensive then previously discussed techniques, but it opens the door to some really cool possibilities.
We will be using Niagara’s collision trace logic on the CPU to find surface positions near our particle system. We can then use this information to exclude particles from spawning, and setting their initial position.
Like last time, there is two ways to follow the tutorial, either you make it yourself using the descriptions and images, or you copy over the contents of this pastebin to a new module script, and then just use my steps as an explanation of the inner workings
Here is a pastebin to the raw code of the module, you can past this inside of your module editor and it will convert it to nodes.
don’t forget to plug into the Output node after copying.
Also in case you are not going to follow the rest of the tutorial, this will only work on CPU in this form.
Make a new module script and call it something cool.
- Open up the module.
- Add a new float input for MaxRadius
- Also bring in Engine.Owner.Position, this is the world position of your particle effect.
- Add a Random Point in Sphere node, this function will generate a random direcion.
It comes with the engine and is used in Sphere Location, so it is thouroughly tested
- We are going to want to normalize this just in case.
(I set the values to 1 so this shouldn’t be nececary, but the normalize doesn’t cost much, and not having the vector be normalized will seriously mess with the code)
- Next, Multiply this direction with MaxRadius and add Engine.Owner.Position. This will be our worldspace endpoint.
- You could drag this value straight into the next Step, but I like to add it to a local for readability
- Pull out a new map get node and add a Collision Query Parameter to it.
- Also add Engine.Owner.Position again, and Pull out the local Trace End.
It is possible that adding the Engine.Owner.Position node twice has a small perfornance cost, I’m pulling it out here to make our spagetti slightly more readable.
- Call the “Perform 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 will Raycast between Start and End and give us some results.
- We want our collision to be valid if the trace returned valid and is not inside a mesh.
- For now we just save the values we are interested in to the map. The new valid bool, the collision position and the collision normal. For this tutorial, you will not need the normal, but it is usefull nonetheless.
- If you want the most barebones implementation, you can skip this step, Just connect Collision world Position to Particles.Position and this will work; However it never hurts to have some options when creating.
- Pull out the local collision valid bool as well as the position and normal from the last step.
- Also add a set intrinsic bool input and the Particles.Position
- To make sure we have a reasonable in case of an invalid collision, use an if node to set the position to TraceEnd.
- I’m also adding this seperate set intrinsic check in case I want to calculate all the values and have something to read from, but don’t want to change the position of my particles when I call this module.
- Add a KillInvalid bool input.
- In case KillInvalid is set, and The collision is indeed not valid, we can set DATAINSTANCE.Alive to false. That way particles that do not have a surface to spawn from will not spawn.
And that’s it.
It is useful to expose this module to the library under Location
The highlights will help you identify the type of module in the emitter stack.
And the description is useful for your teammates, or yourself in a few months
Please let me know if you don’t understand something, or if I made a mistake somewhere.