Fluid
This GPU based simulation was inspired by Sørb’s posts on twitter. The simulation uses compute shaders, custom vertex and fragments shaders, and some C# scripts. The fluid is able to receive and apply forces to and from Unity objects. Since the fluid is GPU based, it can handle arbitrarily shaped objects at no additional cost.
The Fluid
The fluid itself is based off this Nvidia GPU Gems article, and this article on vorticity, adapted for a compute shader in a 2D environment. This approach comes with some difficulties. The fluid uses a Lagrangian advection scheme, meaning that rather than the fluid pushing forward, the fluid pulls forward. At face value this seems like it wont make a difference, but it effectively means that if we have a fast moving front of fluid traveling into a stationary area, the stationary fluid wont pull the fast moving front, and the front will disappear (or propagate slower than it should). This isn’t too much of an issue, but it will come up later. Another change I made is rather than using separate textures for each step, I roll all the textures into two buffers which alternate for each step of the process. This lets me modify velocity and pressure in any step I need to, which is useful when it comes to interacting with solids.
Solid Interaction
The real challenge in this project was achieving convincing fluid-solid interactions. To receive force from solids, each solid first renders its current motion to the motion vectors buffer. Problem is, since we are using a Lagrangian advection scheme (see above for explanation), his motion will often just vanish because the solid passes over it before it has a chance to move. The trick is, if we stretch and shift the model in the direction of travel, we can project the motion ahead of the falling object with a custom motion vector pass. Problem solved. It is worth noting that for the actual collision with objects, the fluid reads from the depth buffer. This means that any shape or size of object will work nicely with the fluid, as long as it has a correct depth pass.
The next issue is how to make the fluid affect solids. First I pull the data off the GPU asynchronously.
The data is not pulled from the main buffers as it would force the main computation thread to wait for the data to be pulled which is very slow. Instead I copy the data to a dedicated buffer, then read from that buffer. Next, each object has a set of fluid force points connected to it. As the name suggests each of these points samples the fluid data, taking into account the velocity of the fluid and the pressure, and voilà! The object gets pushed around.
References and Attribution
GPU Gems article:
https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch30.html
Vorticity confinement article:
https://softologyblog.wordpress.com/2019/03/13/vorticity-confinement-for-eulerian-fluid-simulations/
Bust model from:
https://sketchfab.com/3d-models/spider-man-bust-d655eb29354949149a5ae57299da740e
Background from:
https://assetstore.unity.com/packages/2d/textures-materials/dynamic-space-background-lite-104606
Asteroid models from:
https://assetstore.unity.com/packages/templates/systems/space-graphics-basic-pack-119857