I've been playing around with the idea of hydrodynamic physics on objects in the water, here's my first milestone!
There are several forces that come into play, which are drawn in the video. To calculate them all, the first step is to figure out how much of the object is underwater. To do this, I'm clipping the object's mesh to the plane of the water. The yellow wireframe in the video is the result.
From there, buoyancy is the first force. It's proportional to the volume of the underwater mesh, and the force pushes upwards at the center of the underwater part. It's the single upwards line on each object in the video.
Drag is the next force. Drag is calculated for each face and is proportional to the area of that face. If a face is perpendicular to the direction of motion it generates a lot of drag, and the drag decreases to 0 as you decrease the angle towards parallel. Think of the change in resistance as you move your hand through the water while tilting it.
Lift is the last force. Where drag opposes the direction of motion, lift is at a right angle to it. It's calculated per-face at the same time as drag. In the video, you see my boat hull rise out of the water due to lift, by the end you can see the lift vectors joining the buoyant vector on the boat.
At the end of the video, things get unstable and the boat spins out. This might be a bug in my logic, unbalanced forces on the hull, floating point error, or just bad hull design (this is basically the equivalent of a rowboat with an outboard engine on the back). I'm going to try to build a V-shaped hull to see if it helps resist turning, and if needed also make some super-simple test meshes to help isolate the forces for easier debugging.
Following that, my next steps are to turn this into a module and improve the propulsion system. I've gotten this to the point where I'd like it to be its own node type, so I can attach a GDScript on top of it for driving, steering, etc.