Search Unity

Drag factor, what is it?

Discussion in 'Scripting' started by klumhru, Apr 13, 2011.

  1. klumhru

    klumhru

    Joined:
    Jun 25, 2010
    Posts:
    32
    What does the rigidbody.drag value represent?

    Is is the Reynolds number or something arbitrary in PhysX? I can't find any info on it, besides "it's drag". What I'm mostly seeking is information on the formula by which it affects the velocity of the rigidbody.

    I'm truly curious.

    Regards
    Klum
     
    juanitogan and Jaqal like this.
  2. vreference

    vreference

    Joined:
    Mar 22, 2011
    Posts:
    154
    I'm pretty curious about this as well. Seems like a Cd would have been most useful number for most of to use but realistic Cd numbers produce way too much drag. I'm really frustrated with Unity's refusal to commit to Units (lol, so to speak). I assume the devs don't want to label units because they are afraid of scaring people? As it is I'm forced to create a virtual lab as a development tool to try and figure out what in the flying @$* I'm working with here. People who just want to tweak until it looks right can still do that just fine with labeled units.

    ...My other concern is that it looks like scaling objects effects some (but not all) physics calculations which complicates matters even more.

    I'm guessing force numbers are in newtons; anyone figure out angular drive force? I would have expected it to be newton meters but it doesn't look right so far. Now that I think about i, my first round of testing seemed to indicate that "force" definitely was not Newtons but I'd like to believe I had a scaled transform throwing the measurement off.
     
    Last edited: Apr 13, 2011
  3. klumhru

    klumhru

    Joined:
    Jun 25, 2010
    Posts:
    32
    According to my experiments all force/mass numbers are standard metric, (Nm, kg, m). Launching an object with mass 1 with a (ForceMode.Impulse) force of 10 will give it a velocity of 10. All of those make sense and are as per the PhysX API specs.

    What I'm not clear on is what drag is indicative of. I've done in-engine experiments vs graph simulations and drag in unity and drag in simulations do not seem to match up. Calculating Vt does not seem to work as expected either.

    I'd just like to know, is it an arbitrary dimensionless value? If so, fine, I can deal with it, as long as there is a formula for its interaction with the physx world. It would just be good to know.
     
  4. AquaGeneral

    AquaGeneral

    Joined:
    Oct 30, 2008
    Posts:
    126
    The way I think about it is the factor in which the object is able to push the air away. The faster the object is travelling, the easier it moves, however, the coefficient plays a much larger role in the behaviour. This is perhaps not the greatest explanation, but it's my best.

    I worked out that angular velocity (or torque) is in radians per second. I don't like it how the real names of the parameters are replaced with simpler names, and seemingly in rare events simpler units. For example "Bounciness" is the Coefficient of Restitution.
     
  5. klumhru

    klumhru

    Joined:
    Jun 25, 2010
    Posts:
    32
    From my experiments there is some reason to the effect of D on forward velocity, but it does not seem to add up any basic deceleration formula that I can discern.
     
  6. HarvesteR

    HarvesteR

    Joined:
    May 22, 2009
    Posts:
    496
    There should be a law that forces platform developers to document the units of the values they come up with ;)
    I'm also very frustrated by this not knowing what kind of values are expected...

    I'm under the impression that integration might be done like this:
    Code (csharp):
    1.  
    2. newVelocity = (currentVelocity + forces) * (1 - drag);
    3. newPosition = currentPosition + currentVelocity;
    4.  
    Or maybe like this (I'm leaning towards this one):
    Code (csharp):
    1.  
    2. newVelocity = (currentVelocity + forces) / (1 + drag);
    3. newPosition = currentPosition + currentVelocity;
    4.  
    But I can't know for sure... this is from experience with other physics engines, and I think it's fair to assume PhysX is doing mostly the same.

    Most likely there is a lot more to it than just that, but that's how I think of drag in Unity...

    Cheers
     
    Last edited: Apr 13, 2011
  7. andorov

    andorov

    Joined:
    Feb 10, 2011
    Posts:
    1,061
    Drag is defined as a force exponentially linked to velocity, that is in the opposite direction of velocity. I don't know of the PhysX implementation, but typical quadratic drag goes like this..

    dragForceMagnitude = velocity.magnitude ^ 2 * drag; // The variable you're talking about
    dragForceVector = dragForceMagnitude * -velocity.normalized;

    Oddly shaped objects with big flat surfaces hitting the air have a high drag coefficient. At low velocities, your drag coefficient becomes quite pointless.
     
  8. HarvesteR

    HarvesteR

    Joined:
    May 22, 2009
    Posts:
    496
    Cool, that looks about right.

    I guess the best thing to do would be to manually integrate drag in, instead of relying on PhysX's unknown implementation... We have to do it if we want accurate gravity, why not for drag also? ;)

    Thanks for that snippet!! It'll surely come in handy here :)

    For a more realistic approach, it should be interesting to set up a 'least drag' direction vector, and interpolate from that and maximum drag based on the object's velocity in relation to that vector... this would enable for instance, simulating a skydiver, which has a higher terminal velocity when he's going head first, and more drag when he spreads out.

    More realistic than that would involve actually simulating air flow and displacement... and we'd need a fluid dynamics engine instead of a rigidbody physics one ;)

    Cheers
     
    Last edited: Apr 13, 2011
  9. andorov

    andorov

    Joined:
    Feb 10, 2011
    Posts:
    1,061
    Eh, to be honest I wouldn't bother. The quadratic drag formula I gave is itself a simplified version and PhysX likely uses it (or something slightly better). You have to realize that drag is a *very* complex phenomena. My friend who is an aeronautical engineer has modeled programs that go on for days to simulate drag in fluids 'accurately' and even those are approximations!
     
  10. HarvesteR

    HarvesteR

    Joined:
    May 22, 2009
    Posts:
    496
    Yeah, but I'd rather do it myself than work with unkown units and their unknown relations... especially when having control of what's going on is important, like in a flight sim.

    And yeah, realistic drag is a subject for several books and master's degrees... and it requires modelling fluids instead of just rigidbodies and forces... hence my 'least drag vector' idea.

    As an evolution of that, one might go as far as creating different drag values for each axis, as in, forwardFacingDrag, LeftFacingDrag, and so on... I guess that's about as far as one can go before one's sanity is brought into question... ;)


    Cheers
     
    Last edited: Apr 13, 2011
  11. klumhru

    klumhru

    Joined:
    Jun 25, 2010
    Posts:
    32
    Thanks for the input guys.

    @andorov
    That's the formula I've been using, though it's all about velocity. Factoring forces would require mass to be a variable, and it doesn't figure in drag in PhysX afaict. It's limited, but for a simple simulation like this it should be giving fairly predictable results. Problem is it's not doing that beyond certain distances (1000 meters or so) and certain velocities (>150m/s).

    @HarvesteR
    The way I've used to make simple flight dynamic simulations in Unity (and my own Havok powered engine), is use local forces. Unity offers ConstantForce which works ok. AddForceAtPosition can give you angular influences as well, simulating control surfaces.
    If you are looking at having more control over the physics simulation I'd look into integrating an already existing one, such as Havok or the complete PhysX binding. Both are available to hobbyists. Bullet is another decent physics lib, and has a (untested by me) CLI wrapper in bulletsharp.
    None of these are trivial, but almost certainly better in the long run than rolling your own.
    That's a unity pro feature so not open to me yet.

    Thanks for the input guys. I'll keep plugging at it and let you know if I get it going.
     
  12. Antitheory

    Antitheory

    Joined:
    Nov 14, 2010
    Posts:
    549
    For my vehicles (boats, planes) I use my own drag, and set the in-game drag to zero... However angular drag is another matter as it seems remarkably more complex to model accurately. In order to get realistic-but-playable flight physics I had to link the angular drag value to the velocity of the plane, otherwise a slight touch on the control sends the plane spinning.

    I am pretty annoyed that there is no information forthcoming about what the drag values actually do to the rigidbody... obviously they act opposite to the velocity (angular or otherwise)... but it would be nice to have the equation.

    Also I believe there is a bug with the angularDrag as it takes a fraction of a second to "kick-in". No matter what value it is set at, I always have freedom to roll the plane without angularDrag for the first few frames. This creates a really annoying effect where rotations seemingly slow-down for no reason.

    I guess this is because the rigidbody's angular velocity is unreliable?
     
  13. Factoid

    Factoid

    Joined:
    Mar 30, 2008
    Posts:
    69
    Here was something I posted some time ago, should be helpful. Unity does commit to units by default, but it doesn't shoehorn you in, because the math doesn't care. By default 1 unit = 1 meter, so that standard m/s m/s^2... type stuff works. If you're working in imperial, or your model scales are out, then you need to adjust.

    Drag is just a measure of how much velocity is lost per tick. You can use the post below to implement terminal velocity/acceleration dynamics for controlling vehicles.

    http://forum.unity3d.com/threads/34667-Terminal-Velocity
     
    sean244 likes this.
  14. Teeleton

    Teeleton

    Joined:
    Jun 11, 2011
    Posts:
    10
    Not to nitpick, but velocity.sqrMagnitude would be faster, since the engine uses the square root to compute the velocity. taking that and squaring it again is just doubling effort. ;)
     
    sean244 and juanitogan like this.
  15. Dreamblur

    Dreamblur

    Joined:
    Jun 18, 2011
    Posts:
    184
    That was obviously pseudocode. You're trying to put out a garbage can fire serving as a makeshift heater. Great job!
     
  16. Teeleton

    Teeleton

    Joined:
    Jun 11, 2011
    Posts:
    10
    My bad. I guess I've just never seen pseudocode that could be cut and pasted into a c# script and compile without errors before.
     
  17. capyvara

    capyvara

    Joined:
    Mar 11, 2010
    Posts:
    71
    This thread is a bit old, but for reference, the drag field in Rigidbody sets the linearDamping into PhysX actor, so the factor is linear. If you want to implement aerodynamics drag you should apply the force youself.
     
    juanitogan likes this.
  18. Uraani

    Uraani

    Joined:
    May 29, 2013
    Posts:
    3
    i have used this, its quite similar to the box2d drag that unity uses in 2d physics
    float c = timestep
    vector v = current velocity (as in objects current velocity + gravity * timestep)
    float dt = linearDrag
    vector nv = v * 1 / (1 + c * dt) = new velocity
    i have used this thing in trajectory prediction and it works quite well.
     
  19. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    37
    Just made a few tests and it looks like the formula is this:

    Code (csharp):
    1.  
    2. CallFixedUpdate();
    3. velocity = ApplyForces(velocity);
    4. velocity *= Mathf.Clamp01(1-drag * dt);
    5. velocity = ApplyCollisionForces(velocity);
    6. position += velocity * dt;
    7.  
    Some facts about this:

    • "Manual" forces are applied before the drag
    • Drag reduces the velocity by a "fix" percentage based on the current fixedDeltaTime and drag value
    • If the drag value equals or is greater than the fixed frame rate (1/fixedDeltaTime) the rigidbody can't move on it's own.
    • Since collisions are calculated / applied after the drag, they can cause an impuls spike in velocity and movement, but the next fixed frame the velocity will be 0 again unless there are consequential collisions which again apply an impule force. Note: as long as a collision is "active" (as long as collision stay is called) there might be forces applied from the colliding rigidbody. However all momentum that got tranferred will completely vanish the next frame.
    Example: If you have set your fixedDeltaTime to 0.01 you will get 100 FixedUpdates per second. If you set the drag value to 50 and initial velocity of 100 will be cut in half each fixed frame because the "percentage multiplier" is (1 - (0.01 * 50)) == 0.5

    If the drag is 100 or greater the multiplier will be 0 ( == 1 - (0.01*100)). Keep in mind that the default setting for the fixedDeltaTime is 0.02 which gives you a max drag of 50

    I haven't tested when and how Joints apply their forces. If they use the "normal" AddForce mechanics the drag could draw the Joint completely useless. If it's appllied internally after the drag it might have an affect. But keep in mind that no velocity will survive the next frame if your drag >= 1 / fixedDeltaTime

    Conclusion: That's simply a strange approach. I'm not sure if this was different in the past, but anyways the "hint" on the drag field is clearly wrong since a range of (0 to infinity) makes no sense. The manual states the same, so i guess they *wanted* to do something like HarvesteR suggested as the second example:
    Code (csharp):
    1.  
    2. velocity *= 1 / (1 + drag*dt);
    3.  
    but somehow they didn't.

    Determined and tested using Unity 4.5.4f1
     
    Last edited: Oct 29, 2014
    GliderGuy, Elhimp, Glurth and 6 others like this.
  20. S_Darkwell

    S_Darkwell

    Joined:
    Oct 20, 2013
    Posts:
    318
    Derived from Bunny83's answer, the following script is a stand-alone approximate implementation of Unity's drag:

    Code (CSharp):
    1. using UnityEngine;
    2.    
    3. public class PhysicsDrag : MonoBehaviour
    4. {
    5.     public float drag;
    6.  
    7.     private Rigidbody Body;
    8.  
    9.     private void Start()
    10.     {
    11.         Body = GetComponent<Rigidbody>();
    12.  
    13.         Body.drag = 0f;
    14.     }
    15.  
    16.     private void FixedUpdate()
    17.     {
    18.         Body.velocity *= Mathf.Clamp01(1f - drag * Time.fixedDeltaTime);
    19.     }
    20. }
    With just a bit more code, you can re-implement both Unity's gravity and drag, and achieve perfect results:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class PhysicsGravityAndDrag : MonoBehaviour
    4. {
    5.     public float drag;
    6.  
    7.     private Rigidbody Body;
    8.  
    9.     private void Start ()
    10.     {
    11.         Body = GetComponent<Rigidbody>();
    12.  
    13.         Body.useGravity = false;
    14.         Body.drag = 0f;
    15.     }
    16.    
    17.     private void FixedUpdate()
    18.     {
    19.         var velocity = Body.velocity;
    20.  
    21.         velocity += Physics.gravity * Time.fixedDeltaTime;
    22.  
    23.         velocity *= Mathf.Clamp01(1f - drag * Time.deltaTime);
    24.  
    25.         Body.velocity = velocity;
    26.     }
    27. }
    Many thanks to Bunny83 for finally leading me to the solution to my own drag-calculation troubles.
     
  21. paulkopetko

    paulkopetko

    Joined:
    Jul 27, 2015
    Posts:
    2
    To add to Bunny83 and S_Darkwell's excellent answers, as recently as Unity 5.3.4f I found that the Unity Physics drag calculation doesn't seem to use Time.fixedDeltaTime at all. From my brief tests, I believe it uses the DEFAULT Time.fixedDeltaTime amount of "0.02f", regardless of your Fixed Timestep rate. So the code under the hood in Unity is more likely:

    Code (CSharp):
    1. velocity *= 1 / (1 + drag * 0.02f);
    ... so if you ever change the Fixed Timestep under Project Settings > Time, make sure you scale your drag values accordingly.
     
    electric_jesus and Elhimp like this.
  22. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,286
    If that's the case, it's probably a bug. You should file a bug report!
     
  23. waltran

    waltran

    Joined:
    Feb 23, 2017
    Posts:
    18
    I need to control the angular drag only at y-axis without touching anything else. Is this drag formula works for angular drag ?
     
  24. UnityCoach

    UnityCoach

    Joined:
    Mar 9, 2015
    Posts:
    5
    I recently had to touch on Physics, and as I stumbled upon this very same question, I decided to do a little bit of experiment.

    To properly understand how drag works, I decided to recreate it with a custom component.

    I've come to the conclusion that drag applies a counter force equal to the expected velocity increase over the next fixedDeltaTime. To do this, it sums the current velocity plus all forces applied within current FixedUpdate, and applies an opposite force.

    It's like doing the following :

    Code (CSharp):
    1.          void FixedUpdate ()
    2.          {
    3.              // countering gravity if the rigidbody's using it
    4.              if (rigidBody.useGravity)
    5.                  rigidBody.AddForce(-Physics.gravity * Time.fixedDeltaTime * drag, ForceMode.Acceleration);
    6.              // countering constant force if present
    7.              if (_useConstantForce)
    8.                  rigidBody.AddForce(-(_constantForce.force + transform.TransformVector(_constantForce.relativeForce)) * Time.fixedDeltaTime * drag, ForceMode.Force);
    9.              // countering current velocity
    10.              rigidBody.AddForce(-rigidBody.velocity * drag, ForceMode.Acceleration);
    11.          }
    12.          public void AddForce (Vector3 force, ForceMode mode = ForceMode.Force)
    13.          {
    14.              rigidBody.AddForce (force - force * drag * Time.fixedDeltaTime, mode);
    15.          }
    16.          public void AddRelativeForce (Vector3 force, ForceMode mode = ForceMode.Force)
    17.          {
    18.              rigidBody.AddRelativeForce (force - force * drag * Time.fixedDeltaTime, mode);
    19.          }

    General rules of thumb :

    • drag doesn't account for mass

    • with no added force nor gravity, a value of 1 will stop an object of any mass at any velocity over the course of 5 seconds.

    • a value of 5 will make it stop over 1 second.
    Hope this helps.
     
    GliderGuy likes this.
  25. michealcaj

    michealcaj

    Joined:
    Aug 18, 2017
    Posts:
    36


    Hey bro what About friction force
     
  26. unity_PBO6u1sHnyqr2g

    unity_PBO6u1sHnyqr2g

    Joined:
    Sep 9, 2019
    Posts:
    1
    Briefly. Drag may be interpreted as air friction force that do not takes into account weight of object. It is friction that depends only on speed.
     
    Last edited: Sep 19, 2019
    doctorpangloss likes this.
  27. martinasenovdev

    martinasenovdev

    Joined:
    May 7, 2017
    Posts:
    65
    shouldn't line 23 be "fixedDeltaTime"?
     
  28. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,286
    It doesn't have to. From the docs on fixedDeltaTime: