One of the major issues with Lost Loot was that when you are on the surface of the ocean your body did not rise and fall with the waves properly and as a result you could often see under the water without the underwater system turning on. This regularly broke the immersion and additionally there was no way to have anything floating on the water either, such as barrels, crates, or even the little red boat.
This was due to the fact that the project used the Water 4 system provided by Unity which doesn’t expose the wave height and normal for a given position on the surface via script as previous versions have done. Because I wanted to move forward and further develop the project into a more complete game I decided to tackle this and find a solution.
The waves in Water 4 are calculated in the shader using a Gerstner wave generation algorithm. Because this is done in the vertex shader it is not accessible from scripts. My solution for a GetHeight() method turned out to involve several steps.
- Determine the structure of the mesh being used by the shader, such as mesh size, mesh scale, and mesh cells in each dimension.
- Calculate the triangle of the mesh containing the point specified.
- Calculate the offsets of the three vertices in the triangle using the same Gerstner wave algorithm and parameters used in the shader code (converted to C#).
- Add the offsets to the vertices and find the plane represented by the adjusted vertices.
- Adjust the point specified by adding the average of the offsets for the three surrounding points weighted by the distance to the point (this mostly provides horizontal wave motion).
- Project the point specified onto the plane.
Using this approach provided a very close approximation of the wave height at the point specified. The normal of the plane is also used as a quick approximation of the wave normal.
Because I have the proper wave height now, I have also refined the swimming system to pop you above the water or push you below the water which helps to keep you riding the waves nicely. The movement is subtly influenced by your head orientation so you can slide under the water surface more easily by looking down and pop out more easily by looking above. In addition to keeping you riding on the waves I have also removed the issues of jerky movement along the surface of the water if you are holding the vertical movement control up all the time.
Last, I added a nice buoyancy algorithm that will do voxelization of colliders and simulate buoyancy with a series of forces and the wave height at those positions. This provides a nice mechanism for having arbitrarily shaped stuff floating in the water properly. I can now have general debris and things like the little red boat float nicely on the water.
When I have more time, I plan to refine the code further and do some more generalized testing. Once it is ready for consumption I will then do another post or update this one with the source.