It is an reading note of Photon Water System in GDC2023, related about usage of flow map baking, shallow water equation solving for water surface propagation.
The article can’t cover all details, it just a reading note. Implementation details are so complex that it is recommended to have a look on original source.
Outline
Water System:
-
Procedural tools for river, lake, and ocean
-
Offline flow map baking
-
Runtime fluid simulation
-
Buoyancy and boat physics
-
Underwater volumetric lighting
-
Adaptive water mesh tessellation
Fluid simulation
Offline Flow map baking
Flowmap is pre-computed texture using physical-based simulation tool in existing third party software, such as Houdini.
Details about usage see:
The velocity field is stored as a 2d vector map and fetch at runtime.
However, the existing tool is still inconvenience for artists to use and cannot support turbulent flow.
LightSpeed use lattice Boltzmann method for the solution of shallow water equations (LBMSWE) to bake the flow map. The method has severval advantages:
-
Support turbulence flow
-
Simple to implement
-
Highly parallelizable
-
Conservative
Details about LBM see other tutorial.
Solving
The basic LBMSWE algorithm has four steps:
-
Update the equilibrium distribution f α e q f_{\alpha}^{eq} fαeq
-
Streaming and collision
-
Boundary handling
-
Compute macroscopic variables
In fact, after reading, I just review the theroy of LBM but have no idea about baking.
Summarize
To summarize, LBMSWE:
Pros:
-
Support turbulence flow turbulent flow
-
Simple to implement
-
Highly parallelizable
-
Conservative
Cons:
-
Large memory usage
Each cell needs to store 3 distribution values for nine directions
-
Not good for real-time waterfront propagation
Runtime fluid simulation
LightSpeed uses Shallow Water Equation (SWE) to implement height-field based 2.5D fluid simulation.
To solve classic NS equation based on the shallow water assumption:
D h D t + h ∇ ⋅ u = 0 D u D t = − g ∇ ( h + H ) \begin{aligned} & \dfrac{Dh}{Dt}+h\nabla \cdot u = 0 \\ & \dfrac{Du}{Dt} = -g \nabla (h+H) \end{aligned} DtDh+h∇⋅u=0DtDu=−g∇(h+H)

They split world into grid. Water depth h h h are stored at cell centers, velocities are stored at edge centers.

Solving
The solving is split into 3 steps:
-
Height integration ∂ h ∂ t = − h ∇ ⋅ u \frac{\partial{h}}{\partial{t}} = -h\nabla \cdot u ∂t∂h=−h∇⋅u
-
Velocity advection ∂ u ∂ t = − u ⋅ ∇ u \frac{\partial{u}}{\partial{t}} = -u \cdot \nabla u ∂t∂u=−u⋅∇u
-
Apply water pressure ∂ u ∂ t = − g ∇ ( h + H ) \frac{\partial{u}}{\partial{t}} = -g \nabla (h+H) ∂t∂u=−g∇(h+H)
step 1 and step 3 are using discrete format of first order differential.
step 2 uses classic idea of Semi-Lagrangian Method, which see center of grid as particle, backtrace this particle position p l a s t p_{last} plast at last time, sample at p l a s t p_{last} plast and set it as field value at next time.
The way to get p l a s t p_{last} plast is simply regarding velocity doesn’t change over time, so p l a s t = p c u r r − v c u r r Δ t p_{last} = p_{curr} - v_{curr} \Delta t plast=pcurr−vcurrΔt
To summarize: A n e w ( p c u r r ) = A c u r r ( p l a s t ) A_{new}(p_{curr}) = A_{curr}(p_{last}) Anew(pcurr)=Acurr(plast)
It is just my personal conclusion, you can see famous paper Stable Fluid
to get more details.
And the paper author also gave details about implementation of Stable Fluid:
Real-Time Fluid Dynamics for Games
SWE + Particles System
Problem: SWE does not support discontinuous terrain, such as waterfall
Solution: additional particle system, in which each particle carries water
mass and velocity
Steps:
1. Create particles
Go over all edges to determine whether and how many water particles
needs to be created.
-
Determine whether should create waterfall edge based on the difference between neighboring terrain heights and water levels
-
Determine the particle number
Flux Φ = u i + 1 / 2 ,