Composite VFX in Unreal (systems inside systems?) (GPU events?)

ezgif-8d7957f0f4c4ee
Hello!

This is something I’ve been struggling with for ages… and I can’t find many solutions online or even discussions about it. I’m really curious how you guys handle this sort of thing!

What I’m talking about are effects that are sorta “composite”. Here in this example I have lightning is made up of beams/ribbons, but also spawn a burst of particles at the tail end, as well as a point light. The beam ends slide across the surface a bit. I say composite cause it’s kinda like it’s a system spawning many systems. I have these high-level lightning particles, which are made up of many actual particles (each ribbon particle, the bursting sparks, etc).

You could do it by having the entire system represent a single beam of lightning, and just spawn many of them in Blueprint. This is quite cumbersome however, as you have to do spawn, location (and maybe even a bit of sim) inside of BP, instead of inside of Niagara (which already has all of the tools for it). Performance is also a big concern as you’re spawning dozens of systems.

You could also do this via events. The big limitation being obviously that they’re are only available for CPU emitters.

Now, what I have in the example is kinda the best I could come up with - the entire effect is all in a single Niagara system, and it supports GPU emitters. It is however enabled by a very hacky hack using PAR. It also features a lot of boilerplate and is very confusing to use. Also I have no idea how reliable it is, given it’s hacky nature - who know’s, it might stop working in a later UE version or something.

This sounds like a natural problem that you would face as you try to make more complex VFX, but I’m getting the impression that Unreal straight up doesn’t support it and most people just settle with simpler stuff.

I’m really hoping I’m wrong about that though, and that there’s an awesome magical approach that would somehow enable this sort of thing! Or maybe I’m just being too petty about it and should just go with the BP approach? Maybe it could be solved with some smart NDC usage?

Have you guys encountered similar limitations? Any suggestions? Thank you!

2 Likes

Perhaps a simpler example I just found from some earlier tests:
UnrealEditor-Win64-DebugGame_LRKWkquDJI

Basically you want a more user friendly parent/child system. This is also something that I really miss from CryEngine. They had an awesome parent child system that allowed for very complex behaviors inside a single particle system. It could spawn entirely new emitters with their own age/lifetimes from parent particles. I used it to make an entire aircraft dogfighting scene with different aircraft fighting each other with missiles and guns.

I have used the PAR for several things but I agree its a bit cumbersome. It is very powerful however and there is a lot of stuff you can do with it. Sadly I think its the only real option if you want to create very advanced behaviors. There used to be some really good videos about the PAR from CGHOW on youtube but most of is his stuff is now behind a paywall. My main go-to for figuring out new things is now ChatGPT.

There is also the “spawn particles from other emitter” modules which supports gpu particles. In the backend it also uses the PAR but it has a bunch of commonly used features nicely packaged up in a module. Its a bit more user friendly than PAR but its more limited in its use case. It does useful things like inheriting age, velocity, lifetimes, color, position etc, as well as a few other features age rejection sampling, but it doesn’t really have the more advanced options like spawning based on parent death or collision that the event system has. It should get you 80% of the way there though.

EDIT: I like the lightning effects you made there. Would you be willing to share your setup for the ribbons and spawning sparks at each end point?

2 Likes

Parent/child is a great way to put it! I’ve never worked with CryEngine before, but I think what you’re describing is precisely what I was hoping to have haha.

The lightning setup is actually made with PAR! I kinda have this nice parent/child system in place, it’s just that it’s a bit hacky and annoying to setup… but it works! With a big caveat.

The idea is that I have a “proxy” emitter where each particle represents an instance of the complete effect (in this case, each represents one lightning tendril). I do some raycasting here, calculate beam tangents, slide the end point over time, etc. The other emitters just read from this and spawn particles for each parent proxy. In these child emitters I spawn particles by reading via PAR “Get Num Spawned Particles”. So if a lightning beam proxy spawned that frame, the beam emitter spawns N particles to make up that beam, and then the particles get the RibbonID via Get ID At Spawn Index using ExecutionIndex divided by N. From there, it’s just a matter of reading the values you care about using PAR, cause you have the persistent NiagaraID saved. The sparks for example are the same, you just spawn N particles when a proxy spawns and read values to get the direction to burst them.

The main problem is that this doesn’t exactly work for GPU emitters. For some reason, Get Num Spawned Particles + Get ID At Spawn Index kinda desyncs and it doesn’t work. Couldn’t fix this in a reliable way. I do have some sort of a solution, but it’s veryy convoluted and it’s where the hacky part comes in. And it has a big limitation that you can’t have both CPU and GPU emitters at the same time reacting to the same proxy… which is why I gave up on this whole fix.

I wish the folks at epic could take a look at it, cause it looks a lot like a bug to me… and even if it isn’t, it’s “fixable” for sure. Above all, I’d love them to glorify this whole architecture and make it into a built in system… but I’d just settle for a little fix on this issue hahaha.

Sorry that I didn’t get super into the details, if it was just code I’d be happy to share it, but it’s kinda difficult when it’s a bunch of Niagara modules all over the place haha. Cheers!

1 Like