🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Buoyancy problem for a boat

Started by
4 comments, last by Randy Gaul 4 years, 11 months ago

Hi

 

I am trying to create simplistic model for boats floating in water in Unity using PhysX but i am not understanding how to get it work properly.

 

I use a single rigid body with a centre of mass as the red dot. Its below the ship's mesh as i read having a lower centre of mass made it more stable. Though i cannot get it to be stable anyway.

 

Each green sphere is a buoyancy force calculation which has this code, and it applies the force upwards at the spheres position:


         _volumeUnderPlane = VolumeBelowPlane();
        if (_volumeUnderPlane > 0)
        {
            // P = 1027 (approx density of water at sea level)
            var force = -_volumeUnderPlane * Physics.gravity * P; 
            _parentRB.AddForceAtPosition(force, transform.position,ForceMode.Force);
        }

Where Volume below the plane is calculated as:


    private float VolumeBelowPlane()
    {
        //water level is always 0 for now
        //math based on https://en.m.wikipedia.org/wiki/Spherical_cap
        var dist = -transform.position.y + _radius;
        dist = Mathf.Clamp(dist, 0, 2 * _radius);
        var dist2 = dist * dist;
        var frac = Mathf.PI * dist2 / 3f;
        var volume = 3 * _radius * frac - frac * dist;
        return volume;
    }

But the result is totally unstable, this is how it looks with a lowish mass:

https://i.imgur.com/LLoVzP5.gif

With a high mass it looks like this:

https://i.imgur.com/WNrO33z.gif

 

I am trying to replicate how assassins creed does it, they used spheres to approximate the buoyancy without it being too computationally heavy, yet they didn't go into any details on how they did the math for it but they did post this image of it:

https://www.fxguide.com/wp-content/uploads/2012/12/immerse_spheres.jpg

 

Am i doing any thing wrong with my math here? I don't know why its so unstable for me.
 

Advertisement

for performance issue i put 20 ships on a dynamic ocean grid and used a simplified 3d volume of a ship (still had a ship hull but with less polys) and i didn't find any performance issues, at all (not to mention it was tested on phone, not to mention calculating form drag, skin drag etc. slicing each ships hull with water planes, determining new hull under the water and computing all the stuff.... really using spheres seems lame.

 

Anyway It looks like your inertia tensor is not calculated properly or you attach the force way where you shouldnt. Maybe you use local notation instead of other one (global or else or else), or even you dont play with real numbers - you should start with real numbers

Aside of these functions of yours with some unknown behavior, which i wont help you with cause i dont use 3rd party engines.

The first thing you should consider is to match buoyancy with the mass of the object, it has to stay afloat

 

then second thing is the fact you maybe cant even code the thing  liek this instead of using some wiffy functions like add force add point... not to mention transform.position THE HELL???, forcemode.force JEEEZUS!!

 



/*
 * Buoyancy effect
 * ******************************************************************************************
 */

vec3 cog2cob_vec 	= vectorAB(pos + ROTATION_MAT * CENTER_OF_GRAVITY, CENTER_OF_BUOYANCY);
vec3 buoyancy_force = vec3(0.0, 1.0, 0.0) * (GForce * SUBMERGED_VOLUME * 999.1026);


vec3 ETorque = cog2cob_vec	*  buoyancy_force;

vec3 elements_torque = ETorque;

then you could


result_force = gravity_force + buoyancy_force + drag_force + thrust_vec;

mat4 inv_rot = ROTATION_MAT;
inv_rot.Inverse();

vec3 local_torque = inv_rot * elements_torque;


vec3 EAngAcc = vec3(0.0, 0.0, 0.0);

if (!betweenorequal(-epsilona,epsilona, Ixx))	EAngAcc.x = local_torque.x / Ixx;
if (!betweenorequal(-epsilona,epsilona, Iyy))	EAngAcc.y = local_torque.y / Iyy;
if (!betweenorequal(-epsilona,epsilona, Izz))	EAngAcc.z = local_torque.z / Izz;



EAngVel = EAngAcc*dt;


AngVel = AngVel + EAngVel;

vec3 vLocalAngularMoment = (AngVel*dt)*RAD_TO_DEG;



vec3 accel = result_force / mass;

vel = vel + accel*dt;
pos = pos + vel*dt;

this one is quite important - angular velocity aint calculated as new each frame, instead you add it up.

 

Secondly you add a damping function that reduces chances of getting NANs and divisions by 0

by the first code of the physics frame

    damp(&vel, 10.0, 0.007);
    damp(&AngVel, 10.0, 0.0005);

 

 

 

not to mention drag caused by other parts of the ship etc, sucction force imo is a reaction so you shouldnt consider calculacting that

Why do you need the green spheres? Can you not calculate the buoyant force precisely, computing the water pressure at each face?

They are a simplifications. A real ship gets overwhelmingly complicated quickly. To precisely calculate the forces in such a dynamic system one would at least need:

- the shape of the hull and the construction waterline.

- center of mass and center of lift to calculate righting moments from the static forces. Weight distribution and heel angle play a role here.

- pressure point of the wind force, to calculate righting and turning moments induced from the sails. Easier for a for- and aft rigg (the typical sloop), but a tall ship like in the op is something much more complicated (basic Wikipedia article on wind forces).

- other dynamic forces, resulting from movement of the whole thing in water and wind. These can be decisively strong when underway. Example: rudder and keel, drag and differences in displacement.

My naive idea would be, if one wants it somewhat more realistic, to pre-calculate or -define polar curves for the moments and look up values for certain situations, interpolating between them. Don't ask me for detail, pls ?

 

For a more simplistic model, how about (suggestion) just looking at the two centres of lift and mass. Assume the centre of mass is stable (or calculated when in harbour and after being loaded) and the centre of lift wanders around it depending on whatever dynamic aspects one needs. That way you only have a lever between the two centres and a resulting vector. You only have to take into account the righting force from the angle and the distance between the two centres.

But you don't need the balls any more. Don't forget to model a dampening effect.

 

Edit: btw. modelling flight is easier ?

I used the wrong terms. Pls. replace lift with displacement. I didn't mean aerodynamic lift on the sails, but the force that counters the weight of the boat immersed in water. Sorry for being incorrect. Still, the suggestion might be worth thinking over ... ?

On 7/9/2019 at 4:35 AM, alvaro said:

Why do you need the green spheres? Can you not calculate the buoyant force precisely, computing the water pressure at each face?

You sure can 

 

This topic is closed to new replies.

Advertisement