I've replaced the code that checks if the entity is in the water just by the following:
Checking only the position of the entity to determine if buoyancy should be computed will tend to produce nasty oscillatory behavior. Consider what happens if the position is just barely above the surface, but the boat's hull extends under the water. Under this system, no buoyancy is applied and the boat will 'fall' into the water until the position hits the surface. Then, it will find that the hull is quite deep and apply a large buoyancy force, pushing it out of the water.
I've replaced the upvector with the normal of the wave
While this could produce some types of desired behavior, it will confuse other parts of the system.
One possible 'proper' solution would look something like this:
1) Since the surface of the water is no longer a flat plane, the bounding box based early outs at the start of the GetBuoyancyInformation are less useful. They could still be used if you could grab the minimum and maximum
water surface heights for comparison against the maximum and minimum of the entity bounding box, but doing that probably won't be worth it unless you have an appropriate acceleration structure built for the water surface (which probably doesn't exist, and if it doesn't, it's probably not worth adding).
Note: If you remove these early outs, keep an eye out for later systems that may have depended on the guarantees offered by the early outs. I may have forgotten about some since it's been a while since I've fiddled with the FluidVolume.
2) Embrace the columnar numerical integration used by the fluid volume to detect submerged volume.
Some background:
This numerical integration works by checking a grid of rays against the entity. The rays originate at the bottom of the entity's bounding box and point straight up. Each ray corresponds to a column of volume. If the ray hits the entity, it will use a second ray starting in the same horizontal location but at the water surface and pointing down.
The height between the lower ray intersection and the upper ray intersection gives the height of the submerged column. The size of each grid cell in the integration (given by the number of samples per dimension and the size of the bounding box) gives the width and length of the column. Multiplying these together gives you the approximate submerged volume of the entity for that column.
This process is repeated for all grid samples. The more samples are used, the more accurate the resulting submerged volume is.
The necessary modification:
Right now, a "maxLength" is passed into each call of the GetSubmergedHeight method. It represents the distance from the ray origin to the surface of the water. In the current system, the surface of the water is always at y = 0. You'll need to replace this with the distance from the ray origin to the water surface at each ray sample's horizontal location. So, move the definition of maxLength inside the sampling loop and change it to:
Code: Select all
float maxLength = GetWaveHeight(horizontalLocation) - entityBoundingBox.Min.Y;
Note: All of this integration takes place in the FluidVolume's local space. Watch out for this when sampling your wave function; make sure you're picking the right place or the graphics will be offset.
3) Make sure the bounding box of the fluid volume contains the highest waves.
4) Probably a couple of small things I've forgotten about
By doing all of the above, the integrated center of submerged volume will be in the correct location. This gives you 'rolling' behavior (when a wave hits the side of the boat, the submerged volume will tend to be on one side, so most buoyancy force will be on that one side, and gravity will pull down the other side) and 'surfing' and just about everything else.
The above won't simulate horizontal 'flow' behaviors, though. If you have a particularly large wave which is expected to cause an undertow or similar flow effect, you could apply arbitrary horizontal impulses separate from the buoyancy.
I should mention that revisions to the fluid volume, possibly containing changes like this, could show up eventually- but it could be months or even more than a year. FluidVolumes aren't exactly the highest priority
Very nice