Search Unity

Mass based Buoyancy.

Discussion in 'Scripting' started by Nimerion, Jul 24, 2014.

  1. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Hey guys,
    I'm making water surface physics and I need to make Buoyancy.
    Currently I'm using the fact that:
    Fg - Force of gravity
    Fb - Buoyancy Force


    Fg = mass of body * gravity acceleration
    Fb = volume of body * gravity acceleration


    I saw the rules here: http://scienceprimer.com/buoyancy

    I think I've got the forces calculated right.
    Now my problem is, how can I exert them to my rigidbody (box that will float on the water surface), in a way that can imitate buoyancy?

    This is my code:


    Code (CSharp):
    1. public class physBuoyancy : MonoBehaviour {
    2.  
    3.         bool inWater;
    4.         float damping;
    5.         float buoyancyForce;
    6.         float forceOfGravity;
    7.    
    8.         float mBodyVolume;
    9.         float mBodyLength;
    10.         float mBodyWidth;
    11.         float mBodyHeigth;
    12.         GameObject mesh;
    13.  
    14.         // Use this for initialization
    15.         void Start () {
    16.             inWater = false;
    17.  
    18.             GameObject rigBody = GameObject.FindWithTag ("droppingBox"); // getting my cube
    19.        
    20.  
    21.             Mesh bodyMesh = rigBody.GetComponent<MeshFilter> ().mesh; // getting the mesh of the cube
    22.             Bounds bodyBounds = bodyMesh.bounds;
    23.  
    24.             mBodyLength = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.x, 2.0f) + Mathf.Pow(bodyBounds.max.x, 2.0f));
    25.             mBodyWidth = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.z, 2.0f) + Mathf.Pow(bodyBounds.max.z, 2.0f));
    26.             mBodyHeigth = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.y, 2.0f) + Mathf.Pow(bodyBounds.max.y, 2.0f));
    27.  
    28.  
    29.  
    30.             mBodyVolume = mBodyLength * mBodyWidth * mBodyHeigth * 7.48f;
    31.             Debug.Log(mBodyVolume);
    32.         }
    33.  
    34.         // Update is called once per frame
    35.         void Update () {
    36.             if (inWater) {
    37.                 calculateBuoyancy ();
    38.             }
    39.         }
    40.  
    41.         void OnTriggerEnter(Collider collider){
    42.             inWater = true;
    43.             calculateBuoyancy ();
    44.             rigidbody.drag = buoyancyForce;
    45.             rigidbody.angularDrag = 1f;
    46.  
    47.         }
    48.  
    49.         void OnTriggerExit(Collider collider){
    50.             inWater = false;
    51.             rigidbody.drag = forceOfGravity;
    52.             rigidbody.angularDrag = 0.2f;
    53.             //Debug.Log (inWater);
    54.         }
    55.  
    56.         void calculateBuoyancy(){
    57.  
    58.             forceOfGravity = (rigidbody.mass) * (-Physics.gravity.y);
    59.             buoyancyForce = (mBodyVolume) * (-Physics.gravity.y );
    60.             //Debug.Log (buoyancyForce + " : " + forceOfGravity);
    61.             float buoyancy = buoyancyForce - forceOfGravity;
    62.             Vector3 buoyantForce = Vector3.up * buoyancy;
    63.             rigidbody.AddForce (buoyantForce);
    64.  
    65.         }
    66.     }

    I'm not quite sure, how exactly the "drag" works, but currently what happens is that my cube is just jumping on the top of the mesh and doesn't sink at all.
    Am I going in the right way?
    Or I don't use the API correctly?
    Sorry for the bad english.
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    Code (csharp):
    1.  
    2. mBodyVolume = mBodyLength * mBodyWidth * mBodyHeigth * 7.48f;
    3.  
    what is the 7.48?


    I think you're also missing a step with the way the volume is being used in the CalculateBuoyancy() function. I think you need to work out the submerged volume rather than applying the entire volume. When the object first hits the water it'll not be entirely submerged so it won't displace it's entire volume's worth of water.
     
    Last edited: Jul 24, 2014
  3. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    1 Cubic Foot is 7.48 galons, so I was converting it from cubic feet to galons for the density formula, but I figured that I just need the forces so I coppied the volume formula for my body... (I removed the 7.48 now. :D)
    You're right for the submerged volume.. I'll think about this now, but currently I have no idea how to track, how much of my object "sank" underwater.

    I was dividing the volume and the mass by 1000, but then I thought that I don't need to convert them like that, because my object just kept on sinking. (Don't know if I'm correct here)
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    ah ok, unity's unit system is based on 1m, 1kg etc. (99.9% sure about that at least :) )

    If you want to work in another "unit" you'll need to be careful about applying the conversion consistently.
     
  5. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Ok, I figured that to calculate the submerged volume I need the volume of the object (v) the density of the water (wd) and the density of the cube (d).

    submerged volume = v * d / wd

    Now my code looks like this:

    Code (CSharp):
    1. public class physBuoyancy : MonoBehaviour {
    2.     bool inWater;
    3.    
    4.     float buoyancyForce;
    5.     float forceOfGravity;
    6.     float waterDepth;
    7.     float waterWidth;
    8.     float waterLength;
    9.     float waterDensity;
    10.     float waterMass;
    11.     float waterVolume;
    12.  
    13.     float mBodyVolume;
    14.     float mBodyLength;
    15.     float mBodyWidth;
    16.     float mBodyHeigth;
    17.     float mBodySubmergedVolume;
    18.     GameObject mesh;
    19.     Bounds bodyBounds;
    20.     Bounds bounds;
    21.     float mBodyDensity;
    22.  
    23.     Vector3 buoyantForce;
    24.  
    25.     // Use this for initialization
    26.     void Start () {
    27.         inWater = false;
    28.  
    29.         GameObject rigBody = GameObject.FindWithTag ("droppingBox");
    30.         mesh = GameObject.FindWithTag ("waterPlane");
    31.         GameObject mesh2 = GameObject.FindWithTag ("waterBottom");
    32.  
    33.         Mesh meshFilter = mesh.GetComponent<MeshFilter>().mesh;
    34.         bounds = meshFilter.bounds;
    35.  
    36.         waterDepth = Mathf.Sqrt(Mathf.Pow(mesh.transform.position.y, 2.0f) + Mathf.Pow(mesh2.transform.position.y, 2.0f));
    37.         waterLength = Mathf.Sqrt(Mathf.Pow(bounds.min.x, 2.0f) + Mathf.Pow(bounds.max.x, 2.0f));
    38.         waterWidth = Mathf.Sqrt(Mathf.Pow(bounds.min.z, 2.0f) + Mathf.Pow(bounds.max.z, 2.0f));
    39.  
    40.         waterVolume = waterDepth * waterLength * waterWidth * 7.48f;
    41.         waterMass = 9.11f * waterDepth * waterLength * waterWidth;
    42.         waterDensity = waterMass*waterVolume;
    43.  
    44.         Mesh bodyMesh = rigBody.GetComponent<MeshFilter> ().mesh;
    45.         bodyBounds = bodyMesh.bounds;
    46.  
    47.         mBodyLength = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.x, 2.0f) + Mathf.Pow(bodyBounds.max.x, 2.0f));
    48.         mBodyWidth = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.z, 2.0f) + Mathf.Pow(bodyBounds.max.z, 2.0f));
    49.         mBodyHeigth = Mathf.Sqrt(Mathf.Pow(bodyBounds.min.y, 2.0f) + Mathf.Pow(bodyBounds.max.y, 2.0f));
    50.  
    51.  
    52.  
    53.  
    54.         mBodyVolume = mBodyLength * mBodyWidth * mBodyHeigth;
    55.         mBodyDensity = mBodyVolume * rigidbody.mass;
    56.     }
    57.  
    58.     // Update is called once per frame
    59.     void Update () {
    60.  
    61.         if (inWater || (!inWater && transform.position.y < mesh.transform.position.y)) {
    62.             calculateBuoyancy ();
    63.         }
    64.  
    65.     }
    66.  
    67.     void OnTriggerEnter(Collider collider){
    68.         inWater = true;
    69.         rigidbody.drag = buoyantForce.y;
    70.     }
    71.  
    72.     void OnTriggerExit(Collider collider){
    73.         inWater = false;
    74.         rigidbody.drag = forceOfGravity;
    75.     }
    76.  
    77.     void calculateBuoyancy(){
    78.         mBodySubmergedVolume = mBodyVolume * mBodyDensity / waterDensity;
    79.         forceOfGravity = (rigidbody.mass) * (-Physics.gravity.y);
    80.         buoyancyForce = (mBodySubmergedVolume) * (-Physics.gravity.y );
    81.  
    82.         float buoyancy =  forceOfGravity - buoyancyForce;
    83.         buoyantForce = Vector3.up * buoyancy;
    84.         Debug.Log(buoyancyForce);
    85.         rigidbody.AddForce (buoyantForce);
    86.     }
    87. }
    88.  
    I hope everything is how it should be in the calculations..
    The problem now is that my Cube is constantly jumping out of the water and diving in with the same distance.
    Do I add the forces correctly?
    I'm new to unity, and I'm not too sure how to use the "AddForce" method and the "drag" members..
     
  6. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Update:
    I realised that when I give more mass to my cube, it floats better than when I give it less mass.
    So I saw how many mistakes I've let in my formulas..

    The forces of gravity and buoyancy are calculated like:
    Density = mass / volume and not Density = mass * volume (Sleep before you code! :D)

    The next thing I realised is that I'm multiplying my forces by the same direction of the gravity acceleration.
    Assuming what is written in the link I've posted we have:
    Force of gravity = mass of body * gravity; // gravity = - 9.8 m/s/s for downwards
    Buoyancy force = body volume * (-gravity); // - gravity = + 9.8 m/s/s for upwards


    Then I combine them to figure out the net force.

    I am calculating my submerged volume by in the end I guess I don't really need it.
    I use my full body volume because that's how much water is going to be displaced.


    In the end my box dives in the "water", and then when it pops up above the water surface it just keeps up on bouncing there.
    I can feel that I'm pretty close, but I still can't figure out how to add the forces on the rigidbody object..
     
    Last edited: Jul 27, 2014