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. We are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here: unity.com/legal/terms-of-service.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

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
     
    FlightOfOne, 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:
    141
    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:
    513
    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:
    513
    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
    FariAnderson likes this.
  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:
    513
    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:
    183
    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:
    80
    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:
    2,218
    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
    JMEJAY, Eluem, Alex_Galsan and 11 others like this.
  20. S_Darkwell

    S_Darkwell

    Joined:
    Oct 20, 2013
    Posts:
    320
    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:
    3
    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.
     
  22. Baste

    Baste

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

    waltran

    Joined:
    Feb 23, 2017
    Posts:
    36
    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.
     
    NotaNaN likes this.
  25. michealcaj

    michealcaj

    Joined:
    Aug 18, 2017
    Posts:
    188


    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:
    67
    shouldn't line 23 be "fixedDeltaTime"?
     
  28. Baste

    Baste

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

     
  29. FariAnderson

    FariAnderson

    Joined:
    Jan 20, 2020
    Posts:
    21
    According to NASA, Drag is related with Velocity^2, so the Drag number in Unity can be an approximation of the rest of this formula because according to this, in reality this number is not even constant because the Area towards the Velocity can change, and unity doesn't care about the shape of the object :)
    https://www.grc.nasa.gov/www/k-12/rocket/drageq.html

     
  30. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    28,174
    Please try not to add speculation to to 10-year-old threads. If you have a new question, create your own new post. It's free.

    How to report your problem productively in the Unity3D forums:

    http://plbm.com/?p=220

    You are assuming a lot about Unity's drag calculations.

    This guy seems to have done some actual empirical research into what Unity does:

    https://answers.unity.com/questions/49001/how-is-drag-applied-to-force.html

    From that, it appears to be a linear drag term, not quadratic.
     
  31. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57

    Does this mean that the only way to implement drag manually and have it work the same as default requires also manually implementing gravity?

    Also, as per Bunny83's post the built in drag happens after all other forces. So does that mean you'll still get a difference in behavior if you add forces to objects in other FixedUpdates because your drag might get applied before some of them?

    We need a LateFixedUpdate if we want to be able to fully override drag accurately, don't we? Or am I missing something? :p
     
  32. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    2,218
    No since FixedUpdate is run before the internal physics update. That means all of the FixedUpdate callbacks.

    The question is why do you want to implement drag "manually" and if you really need it manually, why does it have to be like the default drag in Unity? The only real reason to implement your own drag is to either implement a better / different drag (since the one Unity uses does not represent real world drag in any way) or to replicate the physics behaviour outside of Unity (for example on a server).
     
  33. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    I'm a little confused by what you're saying here. So, when you apply forces, nothing happens to the velocity until after FixedUpdate. Wouldn't this mean that if I manually implement drag in FixedUpdate, it would always be running one frame later than if it was working normally for everything (but gravity if I manually implement that as well)?

    I haven't tested it yet. I know that it was having issues with gravity when I first started experimenting with this. My manually implemented drag seemed to be running before the built in gravity. My object with manual drag would fall slightly faster than the built in drag. When I implemented gravity manually as well, as @S_Darkwell did, I was able to get them to fall at the same speed.

    I'm just concerned now that it will still not be accurate to built in drag when other forces and physics interactions are applied.

    I want to extend the drag functionality to allow me to define different drags in different directions relative to the object's orientation. I'd like it to function exactly as Unity would by default, simply for consistency. Ideally, it would simply work exactly like Unity but with this extra feature.

    I'm trying to build some simple behaviors that allow me to extend some of the physics features for a Rigidbody character controller I'm working on.
     
  34. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    2,218
    Basically, yes. The internal physics update happens after your FixedUpdate call. So you can not "see" the results of any AddForce calls during this physics frame. Keep in mind that drag is even applied before the collision forces are applied. So Unity itself has a one frame delay here as well. Since the drag implementation is not related to anything that resembles drag in real life, it doesn't really matter. You can not jumpt in between the internal physics update to alter the way Unity handles drag. Even a LateFixedUpdate would not help because the collision forces would have been applied already at that point.

    I still see no point is trying to mimic Unity's horrible implementation of drag. It's just a percentage reduction of the velocity that is even dependent on the fixed update rate. So changing the fixed rate can have a huge impact on what drag does to your object. It actually makes more sense to apply drag after the object "moved" since drag / air resistance is the result of movement through the air. Unity's approach would completely eliminate any forces if the drag factor is greater than the fixed update rate, no matter how large the force is. So having a one frame integration delay is actually more desired mechanic. Also don't forget that the Physics update as well as FixedUpdate usually runs at a slower rate than the visual framerate. So you often have a one (visual) frame delay.

    ps: Note that I made those tests in 2014 and I haven't repeated those tests since then. So I can't guarantee that the current implementation of PhysX in Unity works still the same. Also note this was just about 3d physics. Physics2D uses Box2D and therefore a completely different physics engine.
     
    Eluem likes this.
  35. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57

    Thank you very much for the comprehensive response. My only real reasoning for mimicking the way Unity does it is to have the base implementation of my extension be the same as Unity.

    I'm still a little confused about something you're saying in these two statements:

    -"It actually makes more sense to apply drag after the object "moved" since drag / air resistance is the result of movement through the air."

    -"So having a one frame integration delay is actually more desired mechanic."

    It seems like you're saying that doing it in FixedUpdate is better because of the delay.. but I thought Unity's default drag implementation applies the drag at a later time than if I applied it in FixedUpdate.

    Am I misunderstanding something?

    By the way, I think I have an implementation that is starting to work for me. I just want to make sure that I'm not doing anything silly that will cause problems for me down the line. I feel like I'm still not fully understanding exactly when Unity applies the drag by default and when would be best for me to do it.

    I'm trying to do it by adding an actual counter force.. though I'm having issues with changing it on the fly or turning it off causing this weird infinite rubber banding effect with large drag values, so I might need to clamp it if I can't figure out a way to stop that.
     
    Last edited: May 23, 2021
unityunity