crispigt.

Physics-based buoyancy

2026-04-10
physicsboyancyfloating

what I worked on

Looking at a new floating mechanism. Found this great paper with Unity code:

The first one is more applicable for us. It bases the floating on the volume of mesh triangles submerged under the water, using Archimedes' principle, we calculate the volume of the object that is in the water and apply buoyancy based on that.

For each frame we check if all three vertices of a triangle are under the water, over the water, or intersecting the surface and clip the triangle accordingly. We then get the submerged volume and centroid to apply the buoyant force.

The second repo was a more realistic simulation but way slower so we're skipping that one, though I did like the aesthetic of their demo.

decisions & reasoning

The original paper assumes flat water, which isn't our case. To handle this, we translate vertices to fluid space, essentially moving each vertex down by the amount the wave has pushed it up, so all comparisons can be done relative to a flat plane.

The original version used the divergence theorem to calculate both the total object volume and the submerged volume, with the reference point always at the object's center. This works for flat water but breaks for non-flat surfaces. We moved the reference point to the average of the submerged XZ coordinates so it can better calculate the volume under water.

We also clip triangle edges correctly by finding the intersection point between a submerged and a non-submerged vertex using binary search.

One thing I'm considering: if the boat has a physically accurate floating simulation, will that create problems because the boat isn't actually well-designed in real life? Also, the paper and the repo both recommend using just the hull mesh rather than the full boat mesh, so I'll look into how to do that.

the hydrostatic pressure model

I also implemented an alternative model based on section 4.4 of the paper (which was left unimplemented there). Instead of asking "how much water are we displacing?" we ask "what pressure does the water exert on this triangle?"

We calculate the hydrostatic pressure:

P=ρgdP = \rho \cdot g \cdot d

where ρ\rho = water density (1000 kg/m³), gg = gravity, dd = depth in water. The force on a surface patch with area AA and normal n^\hat{n} is:

F=ρgdAn^\vec{F} = -\rho g d \cdot A \cdot \hat{n}

In code we use the area vector (negative because force pushes against the normal):

Vector3 triForce = -1 * fluidDensity * gravity * triDepth * areaVector;

We then split this into total upward force and total torque. The torque comes from r×F\vec{r} \times \vec{F}, where r\vec{r} is the lever arm from the center of mass. A force on the bottom left of the hull creates a clockwise torque; bottom right creates a counter-clockwise one. If the boat is level, left and right cancel out. If one side is more submerged it gets more force, creating a natural torque back toward equilibrium.

blender

Spun up Blender for the first time to remove interior polygons from our boat model, they interfered with the algorithm since it expects a clean hull surface. Ended up going with the hull-only strategy the paper recommended anyway, so two birds one stone.

what I learned

The buoyancy of the boat now works like a real boat. The mesh-based approach gives much better behavior than the 4-point system.

One note on the signed volume: if the total calculated volume comes out negative due to numerical noise from the vertex-shifting step, we flip the sign. It's not a bug in the algorithm, more of a numerical artifact we handle.

Settled on the pressure model in the end. Probably biased since I spent more time playing with it, but I think it's the right call, the torque behavior feels more physically grounded.