Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bouncing speed problem..

Discussion in 'Scripting' started by Nimerion, Aug 2, 2014.

  1. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Hey guys, I've posted a thread about buoyancy, I've made it myself, but now I'm over a pretty simple problem, that I just can't figure out for days.
    I have a Plane that represents my water surface, I have a cube with a rigidbody attached to it.
    When I drop my rigidbody in the water it starts to float as expected.

    My problem is that the rigidbody looses energy during bouncing up and down, and when it reach a point where the distance between the lifting force is almost equal to the dragging force, the cube is shaking up and down with a very fast speed.
    How can I make it look smoother?
    I tried to use Vector3.lerp, but it didn't work at all... (Or I don't use it correctly..)

    Here's my code:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class physBuoyancy2 : MonoBehaviour {
    5.  
    6.  
    7.     float waterLevel;
    8.     float floatHeigth = 2f;
    9.     float bounceDamp = 0.05f;
    10.     float forceFactor;
    11.  
    12.     Vector3 buoyancyCenterOffset;
    13.     Vector3 actionPoint;
    14.     Vector3 upLift;
    15.  
    16.     float cubeDensity = 0.65f;
    17.     float liquidDensity = 1f;
    18.     float waterHeight;
    19.  
    20.     float forceOfGravity;
    21.     float buoyancyForce;
    22.     float dragForce;
    23.  
    24.     Bounds cubeBounds;
    25.     float displacedWater;
    26.     bool inWater;
    27.  
    28.     Vector3 currentVelocity;
    29.     Vector3 oppositeVelocity;
    30.     float boxDepth;
    31.     float boxHeight;
    32.     float boxWidth;
    33.     float NetForce;
    34.  
    35.     // Use this for initialization
    36.     void Start () {
    37.         GameObject mesh = GameObject.FindWithTag ("waterPlane");
    38.        
    39.         GameObject droppingBox = GameObject.FindWithTag("droppingBox");
    40.  
    41.         Mesh meshFilter = mesh.GetComponent<MeshFilter>().mesh;
    42.         Bounds bounds = meshFilter.bounds;
    43.        
    44.        
    45.         Mesh meshBox = droppingBox.GetComponent<MeshFilter> ().mesh;
    46.         cubeBounds = meshBox.bounds;
    47.  
    48.         boxDepth = cubeBounds.max.z - cubeBounds.min.z;
    49.         boxHeight = cubeBounds.max.y - cubeBounds.min.y;
    50.         boxWidth = cubeBounds.max.x - cubeBounds.min.x;
    51.  
    52.         waterHeight = 5f;
    53.         displacedWater = boxWidth * boxHeight * Mathf.Clamp (waterHeight - (rigidbody.position.y - boxHeight * 0.5f), 0, boxHeight);
    54.  
    55.  
    56.     }
    57.    
    58.     // Update is called once per frame
    59.     void Update () {
    60.         dragForce = 0f;
    61.  
    62.         if(rigidbody.position.y < 0f){
    63.             calculateBuoyancy ();
    64.  
    65.             dragForce = -0.5f * (rigidbody.velocity.y * rigidbody.velocity.y) * liquidDensity * (boxWidth * boxDepth) * 1.33f;
    66.        
    67.             if (rigidbody.velocity.y < 0)
    68.                 dragForce *= -1;
    69.  
    70.             NetForce = forceOfGravity + buoyancyForce + dragForce;
    71.  
    72.             Vector3 nForce = Vector3.up * NetForce;
    73.  
    74.             rigidbody.AddForce(nForce);
    75.  
    76.         }
    77.  
    78.  
    79.     }
    80.  
    81.     void OnTriggerEnter(Collider collider){
    82.         inWater = true;
    83.         rigidbody.drag = 2f;
    84.     }
    85.  
    86.     void calculateBuoyancy(){
    87.         forceOfGravity = rigidbody.mass * Physics.gravity.y;
    88.         buoyancyForce = displacedWater * liquidDensity * (-Physics.gravity.y);
    89.  
    90.     }
    91.  
    92. }
    93.  
     
  2. hammil

    hammil

    Joined:
    Jun 5, 2013
    Posts:
    56
    If two small but opposite forces cause a glitch, the solution would be to forcibly set them to zero. Something like: if lifting is almost equal to dragging AND both lifting and dragging are small, set them both to zero.
     
  3. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    When I set them to 0, my objects are sinking to the bottom. :/
     
  4. hammil

    hammil

    Joined:
    Jun 5, 2013
    Posts:
    56
    How about setting them to be precisely equal?
     
  5. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Code (CSharp):
    1. currentPosition = rigidbody.position;
    2.             Debug.Log(currentPosition - previousPosition);
    3.             if((currentPosition.y - previousPosition.y) <= 0f){
    4.                 forceOfGravity = buoyancyForce;
    5.             }
    6.  
    7.             NetForce = forceOfGravity + buoyancyForce + dragForce;
    8.  
    9.             Vector3 nForce = Vector3.up * NetForce;
    10.  
    11.             rigidbody.AddForce(nForce);
    12.             previousPosition = currentPosition;
    This is what I'm doing, and it's still glitching.. (if you meant someting like this):(
     
  6. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    I think you have to move the line calculating displacedWater in calculateBuoyancy() because it can change when near the surface.
     
    Nimerion likes this.
  7. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Hm, I guess you're right, now the cubes are bouncing in bigger distance, but when they reach a certain value, they just return to the starting bouning value. Is there a way to make the bouncing movement smoother (slower) and to prevent the continuous bouncing?
     
  8. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    The way is... understand WHY they are bouncing then find a way to fix it. :)

    I tryed your script on a box but it float with no gravity if position.y is something between >0 and 5, and fall with gravity if y < 0. No bouncing at all but probably I am missing something in the scene setup.
     
  9. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    For the cube to float, you need to change it's density by lowering the cube's mass From 0 to 0.4 it floats, from 0.5 above it sinks. Then when position.y < 0, it'll change the direction of the drag force. :)
    I think this is the only thing in the editor..

    You're right about the understanding part, but I'm stuck on this one from quite some time, so I decided to ask a guru, so I've posted. :D
     
  10. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    For values of mass like .15 you have a fun behaviour with continuos bouncing of some meters... :)

    If you change the line in Update() with this, it stop bouncing:

    if ((rigidbody.position.y - boxHeight * 0.5f) < waterHeight) { // when the box bottom is underwater...

    Perhaps you can also not limit the dragForce on the Y axis, if you want a bit more of realism. Anyway you dont need to also change rigidbody.drag in OnTriggerEnter .
     
    Nimerion likes this.
  11. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    If at 0.5 mass it sinks is because you use forceOfGravity with rigidbody.useGravity at the same time. Without 2 times gravity a cube sink at about 1.21 mass instead of 1, because you have to apply forces in FixedUpdate().

    I ended up with this:

    Code (CSharp):
    1.     void FixedUpdate ()
    2.     {
    3.         if((rigidbody.position.y - boxHeight * 0.5f) < WaterHeight)
    4.         {
    5.             calculateBuoyancy ();
    6.            
    7.             dragForce = 0.5f * rigidbody.velocity.sqrMagnitude * liquidDensity * (boxWidth * boxDepth) * .33f;
    8.  
    9.             Vector3 nForce = Vector3.up * buoyancyForce + dragForce * -rigidbody.velocity.normalized;
    10.             rigidbody.AddForce(nForce);
    11.         }
    12.     }
     
    Nimerion likes this.
  12. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Great work, and thank you very much, the bouncing seems pretty smooth right now.
    I never saw this. :D
    Btw, I figured out that I was calculating magnitude wrong.
    And after the correction the bouncing appeared where we wanted it to be, here is the change in the start function:

    Code (CSharp):
    1. boxDepth = Mathf.Sqrt(Mathf.Pow(cubeBounds.max.z, 2.0f) + Mathf.Pow(cubeBounds.min.z, 2.0f));
    2.         boxHeight = Mathf.Sqrt( Mathf.Pow(cubeBounds.max.y, 2.0f) + Mathf.Pow(cubeBounds.min.y, 2.0f) );
    3.         boxWidth = Mathf.Sqrt( Mathf.Pow(cubeBounds.max.x, 2.0f) + Mathf.Pow(cubeBounds.min.x, 2.0f));
     
    Fraconte likes this.
  13. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    I just ignored the start function and set the box manually but thanks. I'll give it a try.
     
  14. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    I wonder why you dont simply use cubeBounds.size but I wonder more if your last code works. :)
    Perhaps I am missing something...

    Edit: I think you are using a cube larger (taking diagonal dimensions) perhaps to compensate for the lower drag after I changed the cx value from 1.33f to .33f (to simulate something more like a ball than a box).

    I was wondering of your code because I was thinking to bounds in worldspace... but I see it's local for the mesh.
     
    Last edited: Aug 8, 2014
  15. Nimerion

    Nimerion

    Joined:
    Apr 20, 2014
    Posts:
    42
    Sorry for the ugly code, I will try to describe how I set my stuff:
    Code (CSharp):
    1. float cubeDensity = 0.65f;
    2.     float liquidDensity = 1f;
    3.     float waterHeight;
    4.  
    5.     float forceOfGravity;
    6.     float buoyancyForce;
    7.     float dragForce;
    8.  
    9.     Bounds cubeBounds;
    10.     float displacedWater;
    11.     bool inWater;
    12.  
    13.     Vector3 currentVelocity;
    14.     Vector3 previousVelocity;
    15.     Vector3 oppositeVelocity;
    16.     float boxDepth;
    17.     float boxHeight;
    18.     float boxWidth;
    19.     float NetForce;
    20.  
    21.     // Use this for initialization
    22.     void Start () {
    23.         GameObject mesh = GameObject.FindWithTag ("waterPlane");
    24.         //GameObject mesh2 = GameObject.FindWithTag ("waterBottom");
    25.         GameObject droppingBox = GameObject.FindWithTag("droppingBox");
    26.  
    27.         Mesh meshFilter = mesh.GetComponent<MeshFilter>().mesh;
    28.         Bounds bounds = meshFilter.bounds;
    29.        
    30.         float waterDepth = Mathf.Sqrt(Mathf.Pow(mesh.transform.position.y, 2.0f) + Mathf.Pow(-5f, 2.0f));
    31.         float waterLength = Mathf.Sqrt(Mathf.Pow(bounds.min.x, 2.0f) + Mathf.Pow(bounds.max.x, 2.0f));
    32.         float waterWidth = Mathf.Sqrt(Mathf.Pow(bounds.min.z, 2.0f) + Mathf.Pow(bounds.max.z, 2.0f));
    33.        
    34.         Mesh meshBox = droppingBox.GetComponent<MeshFilter> ().mesh;
    35.         cubeBounds = meshBox.bounds;
    36.  
    37.         boxDepth = Mathf.Sqrt(Mathf.Pow(cubeBounds.max.z, 2.0f) + Mathf.Pow(cubeBounds.min.z, 2.0f));
    38.         boxHeight = Mathf.Sqrt( Mathf.Pow(cubeBounds.max.y, 2.0f) + Mathf.Pow(cubeBounds.min.y, 2.0f) );
    39.         boxWidth = Mathf.Sqrt( Mathf.Pow(cubeBounds.max.x, 2.0f) + Mathf.Pow(cubeBounds.min.x, 2.0f));
    40.  
    41.         waterHeight = 0.05f;
    42.         //displacedWater = boxWidth * boxHeight * Mathf.Clamp (waterHeight - (rigidbody.position.y - boxHeight * 0.5f), 0, boxHeight);
    43.     }
    44.    
    45.     // Update is called once per frame
    46.     void FixedUpdate () {
    47.         dragForce = 0f;
    48.  
    49.         if(((rigidbody.position.y - boxHeight) * 0.5f) < waterHeight){
    50.             calculateBuoyancy ();
    51.  
    52.             //Fd = (1/2) * v ^ 2 * fluidDensity * ( area ) * dragCoefficient
    53.             dragForce = 0.5f * rigidbody.velocity.sqrMagnitude * liquidDensity * (boxWidth * boxDepth) * 1.33f;
    54.  
    55.             //if ((rigidbody.position.y - boxHeight * 0.5f) < waterHeight)
    56.             //    dragForce *= -1f;
    57.  
    58.             //NetForce = forceOfGravity + buoyancyForce + dragForce;
    59.  
    60.             Vector3 nForce = Vector3.up * buoyancyForce + dragForce * (-rigidbody.velocity.normalized);
    61.  
    62.                 rigidbody.AddForce(nForce);
    63.            
    64.  
    65.         }
    66.  
    67.  
    68.     }
    69.  
    70.  
    71.     void calculateBuoyancy(){
    72.         displacedWater = boxWidth * boxHeight * Mathf.Clamp (waterHeight - (rigidbody.position.y - boxHeight * 0.5f), 0, boxHeight);
    73.  
    74.         forceOfGravity = rigidbody.mass * Physics.gravity.y;
    75.         buoyancyForce = displacedWater * liquidDensity * (-Physics.gravity.y);
    76.  
    77.     }
    78.  
    79. }
    I've returned the drag coef to 1.33f because my boxes jumped out of the water when I their mass is too low. Just like a ball would.

    My cube is with a scale factor of 1, and it usualy has aroud 1.90 to 2 mass. (If it's greater than 2 it will bounce underwater which is not what should exactly happen, It has to sink)
    If this is not enough I will attach my full project, it's not a problem for me. :)
     
  16. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    I just wanted to be sure you know that if you have a cube 1x1x1, cubeBounds.size return a Vector3 (1, 1, 1) while your code return a cube of 1.4x1.4x1.4.