While I've been mostly busy this past month with moving house, I have been making a few models and experimenting with making some water physics in Godot. I got thinking about when doing Frogger, about having a section with the frog driving a boat, but didn't really have time.
Anyway as far as I can see there is no built in support for water in Godot using Bullet or internal physics engine, but I figured it couldn't be too hard to hack something together.
Fixed tick rate physics
First things first, I figured a good way of getting physics to work in combination with a fixed tick rate and interpolation. I will probably write a separate post on this, but I was successful in this case by completely separating the physics representation from the rendered object representation (the 3d model etc) in the scene graph. This ensured that any interpolation code on the rendering side did not interfere with the physics.
Next step was to turn off gravity, and add some kind of manual forces to keep the objects around the waterline. It turns out that you have to be very careful how and when to apply manual forces on every tick, so as not to disrupt the simulation. In Godot I achieved this by using the _integrate_forces function, NOT the _physics_process. I found that rather confusingly adding forces (particularly angular) within _physics_process borked the simulation. _integrate_forces on the other hand gives you access to the actual physics state.
My current code to keep objects at the surface is rather simple: It calculates the y offset (y is up in Godot) of the object from the surface, and applies an impulse in proportion towards the sea level. I actually increase this above water for some kind of gravity, but I'm sure I will come to a more robust solution for this, such as turning on real gravity when significantly above sea level.
This works reasonably well, however, there is a problem, boats etc roll around in the water and don't stay upright. Clearly there needs to be some kind of way of 'righting' objects.
I posted a thread to get advice on this (https://www.gamedev.net/forums/topic/700213-angular-velocity-and-water-physics/) however in the end, rather than using a complex and CPU intensive technique to calculate proper buoyancy I have for now opted for a rather simple hack. I essentially calculate how far an imaginary mast is from pointing vertically up, and calculate an angular velocity towards this. The details are in the thread. This seems to work pretty well, at least in the flat ocean case. I may have to either modify this or opt for a more complex technique for large waves.
It was pretty easy to put in some keyboard control to move a boat or similar about, next step was to see if I could get some kind of waves in the ocean. It turns out Godot has a simplified method of writing multiplatform shaders, and it was pretty easy to follow a tutorial and get a vertex shader with some moving waves. This was already looking better but I wanted the boats etc to move with the waves. As there is no way of reading back the results from the shader, I essentially duplicated the shader wave height function in the main code, did some hackery for scaling, and ended up with a function where I could calculate wave height in the game at any location that would match the shader.
My first thoughts were to simply plug in the wave height into the existing buoyancy code, however, probably due a delay between the impulse being applied and having a decent effect, the objects ended up bobbing out of sync with the waves. Due to the velocity being applied the objects tended to overshoot the surface continually. Really I just wanted to have the objects match the surface with loads of friction, so I realised for a hack I could apply the wave height to the rendered representation, and not apply it to the physics. I tried this out and it seems to basically work (for now). The physics is working on a flat ocean, and the waves are added afterwards to what you see. Obviously this is not ideal, there will be collisions in the physics where there would not be in reality due to the wave heights, and there is no momentum due to the waves etc. This is all a work in progress.
Anyway these are the results so far I think it is promising.
Soon I want to experiment with a large world. For a boating game I'd like to be able to travel a long way at speed, and this may cause precision issues if using single precision floats. So I'll see if I can have some kind of scheme where I teleport the player and objects once they move a certain distance from the origin, while keeping the physics and waves consistent. Another alternative is keeping the player at the origin and moving the objects relative to the player, however that might be a nightmare interfacing with the physics engine.