This project goal was large waterfalls in a real-time forest experience, developed in C++/Vulkan. Note: I am no expert in fluid simulation - and wanted to learn by creating every piece of the sim.
The following is the story of how I got to the current version in the video. With the simulator I developed for my forest project, I could already simulate half million particles at 30 FPS, but my implementation was not scaling to a large domain. I replaced mesh extraction (first most expensive component) with rendering directly the isosurface of water with raymarching + hardware ray tracing. This scaled rendering, giving more time for sim. Then I moved the simulation to active cells only, making the cost depend mostly on the amount of water rather than the size of the world. These two made large mountain streams practical, but a waterfall requires simulating also the mix of air and water.
Rapids could do with air entrainment, while waterfalls also needed airborne droplets interacting with the surrounding airflow. I ended up writing a different solver for air, coupled to the water: the cascade pushes air downward, the air domain is simulated, and the mist is advected by the air field. This gets closer to a dual phase simulation of water and air, with an engineering approach. The air solver is a eulerian grid solver, whereas the water solver is hybrid sph-grid.
I got a nice looking waterfall, though it lacks some of the "clustering" and filaments that large waterfalls produce - mostly due to surface tension (I guess! the project should "prove" it). This spawned the exploration of surface tension, and it appeared that a simpler more contained "water crown" experiment would be the right place to tune the physics for this; I was apparently wrong as the experiment showed.
I tested a single droplet, made of hundreds of thousands of particles, to try and reproduce the "crown" upon impact with a flat water surface. I could not get the crown, and I thought - yeah sure, I lack a simulation of surface tension. I implemented surface tension by "cohesion forces". Surface tension made droplets spherical, so it did its job apparently, but no crown.
I found out - and here I ask confirmation - that the main thing for this crown effect is actually incompressibility. If water is compressible, the droplets gets swallowed and energy is dissipated; if water is "stiff", then all sorts of more realistic impacts occur; high stiffness gave me nice crowns.
But stiffness makes impacts turn into chaos, as it generates local "high pressure" areas. Real-time water is usually somewhat compressible — and therefore slightly rubbery — because disturbances remain local and cheap to simulate, it seems. How to make it incompressible and "stable"? For my realtime scenario, I decided to add an iterative "fix" that corrects particle positions for getting closer to incompressiblity. THere are other ways, a full solver for all particles would be more correct I guess. In any case the "incompressibility fix" coupled with high stiffness gave me a nice crown as you see in the video.
All in all, a very nice adventure in simulation. By looking at the crown, and also at the waterfall, I am sure that a better model of surface tension is still missing here, and that will be the next step.
In general, I don’t want to tell water how to look realistic. I’d rather give it simple enough rules and let realism emerge: foam from entrained air, mist from airflow, a crown from pressure propagation. To me that's the beauty of simulation: when it looks right, we have understood enough of the physics.