Niagara: Local space on sockets from Skeletal Mesh Location?

Hiya, I have been experimenting with the Skeletal Mesh Location Module spawning on characters.

Does anyone know if it is possible to make the particles be local space relative to the sockets/bones of a character. So if I have a particle spawned on the hand then they will follow the hand when its moved.
Right now what I get is that the particles will be local space to the whole character, but I want each particle to be locked to the socked they came from. For example currently if I spawn fire from the hand and then the hand moves then the particle will stay in the air.

Any ideas?
Cheers,
/A

Can you not just attach the particle system to the bone and then use local space?

Hiya Tharle. That would work. But I’m testing with a lot of bones. Imagine a character where you have 30 bones. This means I would have to spawn 30 effects which would cause a lot of drawcalls.
I got a semi decent result by Skeletal mesh on the Update (so every frame), that way I force the particle to be attach to the socket every frame. However downside is that velocity and acceleration does not work at all so they will be forever static.
I have had this feature in other engines, where you can have local space to sockets but does not seem like Niagara supports it.
If I could somehow replace the parent.position with the socket.position somewhere in the modules this could possibly work. Since then the local space would use the socket position instead if that makes sense.
Cheers

The whole notion of “local” vs. “simulated” vs. “world” space in Niagara is kinda arbitrary – if you look in the stock modules, they compute each case individually. I just assume everything is in world space and compute emitter-relative transforms where I need them.

So, yeah, using the socket position (if that’s available) is the way to go. Everything in Niagara is a bit DIY that way – they expect you to compute socket/bone space manually.

Hiya, yes the socket position is available.
Just have not figured out how to inject it properly yet. I’m considering adding it to the Solve Forces and Velocity. So maybe like an offset, as the socket move then I move all the particles that belong to that socket with that offset. Right now I read the socket position every frame to get their positions.

I’m considering reading the parent start position and each bones start position at the Spawn.
Now I know their relative start values, then I can do relative comparison every frame to see if they have moved and if the socket has moved then i move the particles that one frame.
One thing that gave me some headache was that I needed to keep track of the particle IDs since the socket positions are read randomly.
I will do some more experiments. Is it possible to change the parent.position and send this into the simulation? I have not found any place they actually read it, but I’m sure they do.

You’d need to group particles by socket, and apply that socket’s transform on each frame. It’s like having multiple, virtual particle sub-systems within one simulation.

Have you tried what @tharlevfx suggested (make a new system instance for each bone)? I’d confirm the performance impact before trying anything else. I suspect Niagara is efficient about how it generates GPU calls. But you can confirm using RenderDoc.

Thanks for the reply FRGFX. Any tips on how to do this grouping?
I was thinking about looking at the particle ID. Maybe have every particle that ends with 1 on socket 1, id ending with 2 for socket 2.
Worth doing a perf test I have not used RenderDoc, good idea!
We almost always do our performance captures on consoles using Pix or similar. My pc has very fast cpu/gpu so the results would not be typical for other computers. Sometimes I consider getting a slow computer to match console platforms but even those benchmarks would probably be misleading due to differences in how the operating system works.

What I do now is that last time I checked every new effect or even emitter creates a new drawcall and drawcalls is always something you want to minimize as much as possible. Lets say we have 30 bones and 3 emitters in each effect, that would lead to 90 drawcalls per character. I had projects were you had a max drawcall vfx limit of around 300 so 90 per character would not work then. I know Epic talked about collapsing emitters into one drawcall for Niagara but as far as I know this has not been implemented yet.

I think a good summary would be to attach to sockets if we are talking about a handful of sockets, but when we have 10+ then I think we have to spawn from the sockets to prevent cost.

Cheers

Quick question. Where is the best place to apply the transform. I was looking into the Solve Forces and Velocity, but when I injected an offset there the particles would just fly off. I wonder if me injecting an offset cause these intrinsict values to change in odd ways. Maybe I should just inject an offset if there is any new movement so I reset it every time.
What would be best is if one could find the places where the Owner.position is applied for local space and replace that with the socket position but I cannot find it anywhere. I wonder if that part is actually exposed for us. I’m pretty new to modules though so could just have missed it.
Cheers!

Exactly what sort of effect are you trying to do here? If it’s an all over body thing (like say a sandman dripping everywhere) then maybe there’s a better non-niagara solution?

For example you could do crossed planes across the whole body and then rig that with the skeleton and use preskinned position in the material to do whole body local effects?

Alternatively you could use vat or wpo to create a skinned animated mesh?

It probably is possible to do what you want with niagara nodes but transforms can be tricky.

I might have a look into it post Xmas break and see if its possible with a custom module.

Cheers
Tom

I was thinking you’d do the sim in a local space, and apply the transform afterward. But now that I think about it, I’m not sure that’s possible due to the solver (the behavior you found).

The emitter position is used all over the place. But since you have multiple groups of particles, I’m not sure that helps. Hmm…

Did you try testing it with multiple particle system instances? (one for each socket) I kinda think the speed is determined by the total number of particles you’re rendering, not the structure of the simulation. I might be wrong, but… definitely worth a test! Sometimes the easiest solution is the best.

Yes, maybe if you described the effect, we’d have some ideas! :slightly_smiling_face:

Hiya guys thanks for all the ideas. Currently my goal is to find limitations in the default Niagara so I do not work on an exact effect.

I can describe previous effects I have done with exactly this technology (local space to sockets)

  • Fire on characters. This was done by having flames being local space to bones so the flames are following the bone positions exactly. The sparks would not be local space so would trail after.
  • Skeletons with ghostly smoke. So attach smoke to their chest arms and legs so they are following the bones
  • Fire on car parts
  • Dripping water. I have also done this with local space before
  • Big monsters that have water falling from their arms.
    Tom is correct that this could be done well with a mesh, but I would say the best result you would get with a combination of mesh and particles. Some parts of water and fire can be done well with meshes, but many parts are done better with particles I think. One benefits with particles is the animated texture sheets can if well done really add quality. It can also be tricky to add meshes to characters since we would not be the actual character modelers so you would then need to get the mesh from the character team and add things after and do skinning etc (I actually made a point to beef up my rusty skinning skills for this reason!).

I guess somewhere in the code we have something like this

Local Space Coordinate System + ParticlePositionRelativeToCoordinateSystem +ParticleSpeedRelativeToCoordinateSystem*DeltaTime

Challenge is we may not have access to the Local space Coordinate System. Ideally we would just replace it with the socket Transform Matrix.
So it could be that what we need to do is keep World Space but do the transform ourselves
So
ParticleWorldPosition + ParticleWorldVelocity*DeltaTime

My first thought was just to inject the Position here so
ParticleWorldPosition + ParticleWorldVelocity*DeltaTime + SocketTranslation
The SocketTranslation would need to be set to 0,0,0 for its first frame, so after that the SocketTranslation is relative to its first position.

Now, one problem with this is you would not get any rotation this way. However this may not be such a big problem. Most of the time rotating the effect with the bone causes more weirdness and normally I would disable all rotation to particles when I attach them to sockets since basically the particle system risk beginning to spin around. I guess one could modify say the velocity Module so it takes the rotation of the Socket into account, so for example the fire is flying away from the body, that would be useful.

If one is ambitious local space is not the perfect solution for effects like this. Ideally it would be “sort of local space” so that the particles mostly follow the characters but that they also trail behind the character. That should be possible to do with Niagara, but I never had it before. One could imagine that one Lerps between a particle being local space to gradually being in world space instead.

I will keep looking into this, its a quite a useful exercise.
Cheers!