Search Unity

Physics drag formula?

Discussion in 'Scripting' started by kebrus, Jun 18, 2014.

  1. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    Hi there, i have this situation where i need to apply different forces to an object and then apply the gravity manually, but this gravity can't factor in the drag nor the mass of the object, meaning i want it to fall down as if the drag was 0 while not being set to 0 in the drag properties

    right now i have this
    Code (CSharp):
    1. rigidbody.AddForce(new Vector3 (0, -gravity * rigidbody.mass, 0));
    this is enough to ignore the mass, but now i need to do some calculation to account for the drag of the object

    i know unity uses physx but i can't find information anywhere how the drag calculation is done inside, even other poster formulas don't seem to work, all i know 0 means no influence and infinity means total influence
     
  2. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    For a linear drag behaviour unlike real air pressure:

    Code (csharp):
    1.  
    2. // Apply gravity
    3. rigidbody.AddForce( Physics.gravity / _drag * Time.fixedDeltaTime, ForceMode.VelocityChange ));
    4.  
    Thats essentially what I do in uPhysics.
     
  3. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    That can't be right, if drag is zero i get to divide by zero?

    Just for the sake of it i actually tried it in a falling cube with a drag of 2 and this script next to a cube without any drag and the first one is slower
     
  4. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Like I said, its a linear behaviour.

    As of the first being slower as the second, of course it is slower. Higher drag means more air friction, means less force/slower acceleration. In the above formular, 1 means no drag at all by the way.

    Just to be accurate, this is a solution for drag, but prolly not the solution PhysX uses. Tho, when modelling physics in games it is not about pure correctness but about it looking good.
     
    Operator08 likes this.
  5. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    In this case i need it to be 100% correct, i have other objects in the scene that use the normal physics and interact with this object, a linear drag from 0 to 1 doesn't work for me because this a situational case where i need to ignore the drag when falling down (other axis should have drag) so the object must fall down just like any other object around it

    I only need to know the formula of how the drag is being used inside the unity, i'm not even sure if this is a physx thing or not because i can't find any explanation if i search for physx
     
  6. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    Bumping this, any help would be appreciated

    I can't believe this isn't documented somewhere, not even in nvidia physx documentation, i just need to know exactly how drag is being used, not a general way like "The higher the drag the more the object slows down." this doesn't help me at all
     
  7. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    I finally got it working!!!!

    I'm gonna explain in detail for future reference in case anyone needs it. I actually stumbled into the solution in a Cocos2D forum thread... ... ...yeah... o_o

    This is how PhysX applies unity drag (or linearDamping as they call it) in pseudo code:
    Code (csharp):
    1. velocity = velocity * ( 1 - deltaTime * drag);
    With that said, reverse engineering still took me a while, had to record values frame by frame and trial and error formulas till i got it right.

    In my case i wanted to apply gravity without mass or drag so this is what i got now:
    Code (csharp):
    1. float veloc = rigidbody.velocity.y * rigidbody.drag;
    2. float force = Gravity; //-9.81f
    3. float coeff = (1 - Time.deltaTime * rigidbody.drag);
    4.  
    5. rigidbody.AddForce(new Vector3 (0, ((veloc + force) / coeff) * rigidbody.mass, 0));
    If you want to apply as a velocity change you have to do it like this (note how mass goes away):
    Code (csharp):
    1. float veloc = rigidbody.velocity.y * rigidbody.drag * Time.deltaTime;
    2. float force = Gravity * Time.deltaTime; //-9.81f
    3. float coeff = (1 - Time.deltaTime * rigidbody.drag);
    4.  
    5. rigidbody.AddForce(new Vector3 (0, ((veloc + force) / coeff), 0), ForceMode.VelocityChange);
    In theory you can use this to any force at any axis or all axis, in my case my force was gravity and i only wanted to remove drag from the y axis.

    Cheers
     
  8. sanjodev

    sanjodev

    Joined:
    May 29, 2012
    Posts:
    63
    Thanks for this kebrus. Me and you think alike. I'm surprised other people aren't as interested in this.
     
  9. nickdas

    nickdas

    Joined:
    Dec 10, 2014
    Posts:
    2
    I've confirmed this still works the same in Unity 5.

    If anyone else wants to play with the physics to get a better understanding for how it works, I have included a script that's basically a re-implementation of rigidbody force and drag.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4.  
    5. public class TransformDropTest : MonoBehaviour {
    6.    
    7.     public float mass = 1f;
    8.     public float drag;
    9.     public Vector3 acceleration = Vector3.zero;
    10.     public Vector3 gravity = Physics.gravity;
    11.  
    12.     private int fixedUpdateTicks = -1;
    13.     public bool atRest = false;
    14.    
    15.     void FixedUpdate() {
    16.  
    17.         //Stop moving if we're at rest.
    18.         if (atRest)
    19.             return;
    20.  
    21.         //Log debugging information
    22.         fixedUpdateTicks++;
    23.         Debug.Log (string.Format (
    24.             "Fixed Update Ticks: {0}\n" +
    25.             "Position: {1}\n" +
    26.             //To derive velocity from acceleration, we need to divide by time
    27.             "Velocity: {2}\n", fixedUpdateTicks, transform.position, acceleration.magnitude/Time.fixedDeltaTime));
    28.  
    29.         //Add the force
    30.         AddForce (gravity, ForceMode.Acceleration);
    31.  
    32.         //Apply Linear Damping (drag)
    33.         ApplyDrag ();
    34.  
    35.         //Move the object
    36.         transform.position += acceleration;
    37.  
    38.     }
    39.  
    40.     void OnTriggerEnter() {
    41.         atRest = true;
    42.     }
    43.  
    44.     public void AddForce(Vector3 force, ForceMode forceType) {
    45.         switch (forceType) {
    46.         case ForceMode.Force:
    47.             //Force mode moves an object according to it's mass
    48.             acceleration = acceleration + force * mass * Time.fixedDeltaTime * Time.fixedDeltaTime;
    49.             break;
    50.         case ForceMode.Acceleration:
    51.             //Acceleration ignores mass
    52.             acceleration = acceleration + force * Time.fixedDeltaTime * Time.fixedDeltaTime;
    53.             break;
    54.         default:
    55.             throw new UnityException("Force mode not supported!");
    56.         }
    57.     }
    58.  
    59.     //Apply Linear Damping
    60.     public void ApplyDrag() {
    61.         acceleration = acceleration * (1 - Time.deltaTime * drag);
    62.     }
    63. }
    64.  
     
  10. NDSno1

    NDSno1

    Joined:
    Dec 20, 2014
    Posts:
    223
    Sorry for bumping but I'm working on the same thing. I'm doing a racing game and I need something to limit the speed and thinking about applying drag. I'm looking for a formula that given the maximum Speed, the added drag will becomes larger with the velocity so that the acceleration cancel out and the car achieve stable max speed. Any help is appreciated.
    Thank you very much and sorry.
     
  11. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    The idea of knowing what unity is doing with drag was to intercept it to do something else. It's not to replace it entirely, you can do it anyway by putting drag and gravity at 0. This way you can do whatever you want with the object.

    I know I'm not giving you ideas in how you can use something to your needs but maybe this topic is not what you need.

    It isn't all lost tho, nickdas script above is a re-implementation of what unity does, you can use that as a base for what you want.
     
    NDSno1 likes this.
  12. ATLGAN

    ATLGAN

    Joined:
    Oct 15, 2017
    Posts:
    10
    Thanks kebrus. Your formula almost worked so i had to make a change. I'm using new formula:

    Code (CSharp):
    1. void FixedUpdate()
    2.     {
    3.         float veloc = rig.velocity.magnitude * rig.drag;
    4.         float coeff = (1 - Time.fixedDeltaTime * rig.drag);
    5.         float force = (veloc / coeff) * rig.mass;
    6.  
    7.         rig.AddForce(transform.forward * force, ForceMode.force);
    8.     }
     
    Last edited: Aug 18, 2020
    forestrf likes this.
  13. jrmgx

    jrmgx

    Joined:
    Oct 21, 2016
    Posts:
    41
    I wonder how the ForceMode.Impulse would be implemented in this example?

     
  14. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,990
    jrmgx and PraetorBlue like this.
  15. ATLGAN

    ATLGAN

    Joined:
    Oct 15, 2017
    Posts:
    10
    I did a little wrong but I fixed it.
     
  16. Le_Comrade

    Le_Comrade

    Joined:
    Apr 5, 2016
    Posts:
    1
    I implemented it but my object is still falling slowly, I'm not sure what I did wrong because I basically just copied the code:

    Code (CSharp):
    1.   void ApplyGravity() // called during FixedUpdate
    2.   {
    3.     float vel = rb.velocity.y * rb.drag;
    4.     float coeff = (1f-Time.fixedDeltaTime*rb.drag);
    5.     float force = ((vel+gravity)/coeff) * rb.mass; // gravity = 9.81
    6.     rb.AddForce(-Vector3.up*force, ForceMode.Force);
    7.   }
    Edit: I figured it out a couple minutes after posting, it's because I made `gravity` positive and was multiplying by `-Vector3.up`, but because I was adding `rb.velocity.y` it was inverted. After fixing it works fine now.
     
    Last edited: Feb 27, 2021