It’s been a while since my last post here, so here I am to change that !
I didn’t really take time to work on any personal VFX project lately, so I’m afraid I don’t have anything visually shiny to share today.
I’ve been working a lot with Niagara inside Unreal, and the one thing that stroke me as a major strengh is how much customizable it can be at any level with the related module / dynamic input / function script. With that said, some of the engine provided Niagara module script looked like they could use some little upgrade, starting with some basic location modules.
Sphere Location module :
The first one I’ve modified is the cylinder location module. In the default module graph, the “hemisphere picking” feature is happening before the “sphere rotation” feature.
Therefore, when you chose some given hemisphere picking and rotate the sphere orientation, the “side” of the sphere picked by the hemisphere will rotate with it since it’s happening first in the maths. That could be a wanted thing depending on specific usages, but it seemed very limitated to me when I had to use it.
First things first, I’ve changed the order of execution of those two features, so now the sphere will rotate first and then pick a sphere side to spawn upon. For the side picking, I’ve chose to get rid of the simplier hemisphere picking, and replaced it with some sphere normal constraint comparison. The sphere will now compare the sphere normal to a user provided axis using cross product, and then will apply a threshold on that result to obtain the particle spawn location.
All of this above allow me : 1. to have some controll over sphere rotation without it having any influence on the world axis contraint / 2. to controll the axis constraint at runtime in a smooth way using dynamic values for axis direction and threshold (for runtime wind behavior for example, that would make possible to make the particle spawn from the side of the sphere that match wind axis).
Below, I’ve just made some simple debug blueprint. The red square foward vector will be the axis constraint, the green square foward vector will be the sphere orientation. (Think of it like the red one being the wind direction, and the green one being the actor rotation for non-uniform shapes)
Static Mesh Location module :
Default static mesh location module is featuring some axis constraint similar to the one I’ve added to the cylinder location. While working on some weapon aura effects, I’ve noticed that the axis constraint was taking place in the same coordinate space than the emitter itself. This meant that if you wanted some world space emitter that would leave some particle behind as the actor mooves, the axis contraint will change as the actor rotate and moove in the world.
My idea here was to let the user choose between world and local space for the axis constraint, and do the “does it need to be inverted from emitter space ?” trick inside the script.
Doing so, I’m now able to have this axis contraint and the emitter working together in different coordinate space. It allowed me to use new behaviors that wasn’t available before :
- Emitter = local + Constraint = local : particle stay around the actor when it moove, particles are spawning on the same side of the mesh no matter what.
- Emitter = world + Constraint = world : particle stay behind in the world as the actor moove, particles spawning side on the mesh is relative to actor rotation.
- (new) Emitter = local + Constraint = world : particle stay around the actor when it moove, particles spawning side on the mesh is relative to actor rotation.
- (new) Emitter = world + Contraint = local : particle stay behind in the world as the actor moove, particles are spawning on the same side of the mesh no matter what.
(see example in video below)
Those new behavior really helped me while working on some weapon/item aura VFX composed with all of those coordinate space combinaison.
The n°3 for example was a really good way to handle smoke spawning on some object. I didn’t want my smoke sprite to stay behind if the player move, I prefered it to “stick” to the object, so local space was needed for the emitter. But I did want the smoke to always spawn on the side of the mesh that was pointing up, so I needed the axis constraint to be world space.
the n°4 was a really good way to spawn sparks on a given side of a mesh (think about some one sided sword, and you would like the spark to only spawn on the cutting edge of the blade), that would need the axis constraint to be local. But I did want those sparks to be world space and stay around with some curl noise as the player was mooving around.
In addition to this axis contraint improvements, I wanted my mesh location module to have more controll on how particles was spawning.
First thing first I’ve added is some “vertex color constraint” that would allow the user to choose a given color channel (R/G/B/A) from the mesh vertex color (that is sampled already by the sample static mesh module). This can be usefull when other ways (like material or axis contraints) are not working for a specific usage.
Then my second idea was to add a “local position threshold constraint”. This one part will let the user choose a given axis, and then allow particle to spawn only if their position value on this axis is above (or below if inverted) than the user provided value. I’ve also added some random range to this threshold, allowing me to create some kind of gradient with particles spawning instead of having particle spawning above a “straight line”. For now, I’ve made this position threshold happening in the mesh space only, because I didn’t want the spawning to change if the player crouched while spawning above a given Z value in world space emitter for example.
Making my first steps in module/input scripts for Niagara really made me realise how powerfull this tool is for being as customizable as possible. Don’t feel limited by the default modules and emitter, just adapt and create whatever feature you need !
I hope this little breakdown has been interesting to you guys, I’d like to find time to make more of those breakdown in the future.
As usual, feel free to share your thoughts about what you just red and to ask questions if you have some!
Thanks for the read, see you soon, and may the VFX be with you as always!