FluXY is a grid-based, GPU, 2.5D fluid simulator for Unity. Let's see what this means:
Any fluid simulation must store the physical state of the fluid at every point in space. This state is mainly:
To perform the simulation (that is, to update the state of the fluid over time) your computer's graphics processing unit or GPU is used. Since GPUs are good at handling textures, and a texture is basically a grid, Fluxy uses textures to store fluid data: each texel in the texture corresponds to a cell in the grid.
Fluxy uses two textures to store fluid state:
Fluid simulation is performed entirely in 2D, but a variety of techniques (billboarding, camera projection, vector projection, inertial forces, etc) are used by Fluxy to endow 2D fluid simulation with a pseudo-3D look. This way you get fluid that looks 3D, but performs orders of magnitude faster.
Fluxy's core is composed of 3 components and 1 asset. Let's take a quick look at them and the role they play:
Fluid state is stored on textures, as previously mentioned. The actual allocation and management of these textures is performed by the FluidStorage asset. Each solver has a reference to one storage asset, multiple solvers can share the same storage. The storage asset will make sure that the combined memory consumption of all solvers using it won’t exceed a user-defined threshold. It does this by re-creating the texture buffers when necessary, according to the desired resolution of each solver, its level of detail (LOD), and other factors.
Each FluxySolver will request a couple of textures from its storage asset: one to store densities, one to store velocities. These textures can be shared by multiple (up to 16) FluxyContainers, this is achieved by using automatic texture atlasing: each container is assigned a rectangular region within the solver’s textures, then the fluid in that rectangle is updated by the solver using the parameters specified by the container (turbulence, buoyancy, viscosity, etc).
Atlasing allows all containers sharing the same solver to be updated in parallel and be drawn in a single drawcall. However, since the containers must share the same texture space, the more containers you assign to the same solver the lower resolution they will have.
FluxyTargets are splatted onto containers, and they “draw” density and velocity values into it. Which container(s) will a target be splatted onto? You can either specifiy this on a per-container basis, or use a FluxyTargetProvider. Target providers are components that live alongside a FluxyContainer, and dynamically determine which targets to splat onto it. There’s a built-in target provider component (FluxyTargetDetector) and you can easily write your own if required.