Smoothed-particle Hydrodynamics in Niagara

It honestly hadn’t occurred to me to look at Unity. Just had a look at Obi Fluid and I’m quite impressed. I’ll have a more thorough look after work.

Regarding your implementation, two loops need to be done in separate stages. There is no point in having two loops, like in your code, because density, you would be working with, will eventually end being density of previous frame, and SPH integration will stop being valid. You need to separate density loop and velocity integration into two separate simulation stages.

I also did not see boundary handling in your code. You can’t just rely on particle collisions alone here, as it would cause particles to stick to boundaries and loose tremendous amounts of energy. Boundary needs to be handled during velocity solve.

Mind, that you need substepping. At typical game framerates you would need a from several to several dozen substeps to have sufficient stability, unless you implement pressure clamping and significant dampening, which reduces realism in favor of performance.

Concerning visualization, for screen space fluid you would need at least custom Niagara interface with capability to draw particles to render target.
Rasterizing them manually in Niagara is very limited in functionality and particle screen size/ distance relation.

Alternatively, instead of using screen space fluid, vowelize density and raymarch through in simulation stage at lower res. Then upsample in material pass.

Regarding mobile, you can implement that all in custom compute shaders without niagara.
Last but not least, expecting realtime SPH on mobiles is gross over-expectation.

Thanks, Deathrey.

As I say, I have the fluid simulation working perfectly well now, and I’m getting 120 fps on my five year old computer (and that’s with four iterations of the simulation stage). There’s no need to separate the density loop and the forces loop into separate simulation stages.

Regarding the boundary-handling, using the built-in signed distance field-based collision module works just fine. However, since that doesn’t work on mobile shader models, I developed my own environment collision system which also works very well, albeit with a slight drop in performance.

Even with tens of thousands of particles I’m still getting 90+ fps. However, there’s never going to be more than a couple of hundred particles in the system for the purposes to which I need to put it; I’m not simulating buckets of fluid. Therefore, I don’t believe it really is a gross expectation for this to run on a mobile device. A mobile device would need be less than 1% as powerful as my old PC for this to be impossible performance-wise, and modern mobile devices are more considerably more powerful than that.

I can’t test it anyway because simulation stages aren’t supported. This is frustrating but since it appears to be possible in Unity, I’m going to try that.

There’s no need to separate the density loop and the forces loop into separate simulation stages.
Oh, but yes, there is need in doing so. Particle attributes, you read, are from before simulation stage begins. Therefore, in density iteration, position of particle iterated upon, will be position from just before the simulation stage, therefore current frame position. Position of neighbor particles will be also from before simulation stage start, that is current frame. So far so good. Density calc is done. But then your saving density to a particle attribute and in the same loop start reading density of pressure projection. Density of particle, you are iterating on, will be from density calculation done in this simulation stage, but density of neighbor particles will be from before simulation stage starts, that is previous frame. This way you are introducing error into simulation and technically waste half of substeps.

Regarding the boundary-handling, using the built-in signed distance field-based collision module works just fine.

It works. But far from just fine. Your particles interact with each other within radius of smoothing kernel, why boundaries should be any different? Just depenetrating and reflecting particle from boundary is very basic and physically incorrect way, leading to poor results. So, yeah, not fine really.

Even with tens of thousands of particles I’m still getting 90+ fps. However, there’s never going to be more than a couple of hundred particles in the system for the purposes to which I need to put it; I’m not simulating buckets of fluid.

SPH shines with high particle count(hundreds of thousands), significant kernel radius and high neighbor particle cap.

Few hundreds of particles is a domain, where just running grid-based solver will yield you same results, while being faster and more stable.

Anyhow, good luck.

One thing I should mention is that my non-SDF environment collision solution handles the collisions in a more realistic way that isn’t just depenetration.

I think I see what you mean now about separate simulation stages. I could have a look at it but unfortunately it’s a waste of time because simulation stages aren’t supported on mobile.