Search Unity

Simulating friction manually

Discussion in 'Scripting' started by Jon-Huhn, May 29, 2010.

  1. Jon-Huhn

    Jon-Huhn

    Joined:
    Jan 26, 2009
    Posts:
    85
    I'm creating a raycast car system, and currently I'm struggling with how to apply friction correctly (for now assume the brakes are locked up and the wheels aren't rolling, therefore it doesn't matter what direction the wheels are facing).

    I know how to find the direction that an object is sliding across a surface (using dot product, the surface normal, and the velocity vector of the wheel), so it's then pretty trivial to use AddForceAtPosition() to apply a constant force in the opposite direction of the movement every FixedUpdate() to simulate kinetic friction between the tire and ground. My problem is in what happens when the object is moving so slow that the friction force I apply actually makes it start to move in the opposite direction.

    Any thoughts on how to determine if a given application of force will be too strong, and if so, determing just the right amount of force to apply to stop the object perfectly on that frame?

    Or maybe another approach altogether?

    Thanks!
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The friction force is actually proportional to the speed of the car in the direction it is moving. If it doesn't matter what direction the wheels are facing, you can add friction with:-
    Code (csharp):
    1. rigidbody.AddForce(rigidbody.velocity * negativeForceConstant);
    ...ie, the friction is proportional to the velocity's magnitude but in the opposite direction.
     
  3. Jon-Huhn

    Jon-Huhn

    Joined:
    Jan 26, 2009
    Posts:
    85
    I agree that air resistance is proportional to the speed(speed squared, specifically), but I think the kinetic friction between two sliding surfaces is independent of speed. Otherwise it will take an unnaturally long time for the object to come to a halt as it reaches low speeds. But I'll give it a try and see how it looks.

    Thanks.
     
  4. TwinFox

    TwinFox

    Joined:
    Jan 9, 2009
    Posts:
    66
    Yep, kinetic friction is independent of velocity. You will, however, never be able to completely stop the wheel by applying forces - you are only able to react to movement once its already happening. This is the reason why the built-in wheel collider always creeps.

    Instead, you can calculate the minimum velocity before direction changes from

    Code (csharp):
    1. v_limit = Time.deltaTime * friction_force / car_mass;
    When you are below this limit, simply zero out the x and y components of the force exerted by the suspension spring to the chassis. You will probably want to also have a drag-like component acting on your wheel to smoothly force the wheel to a complete stop.
     
  5. Jon-Huhn

    Jon-Huhn

    Joined:
    Jan 26, 2009
    Posts:
    85
    TwinFox,

    Will your suggestion work in cases where the car is parked on a hill (in other words when forces, such as gravity, are actively pushing the car)? I've tried zeroing out the velocity, but it continues to creep every frame because from the time I zero out the velocity in one FixedUpdate() till the time I do it again the next time, any forces acting on the car will have pushed it just a little bit.

    The only thing I can think of is somehow for every force pushing the car, there needs to be a friction force applied to resist it in the opposite direction of the force, and also ANOTHER force generated to resist the velocity of the object opposite the direction it's moving. Simply reacting to the velocity isn't enough to lock the tires on the road, forces need to be reacted to as well.

    My guess is this is where Static versus Kinetic friction forces are used... but at the moment it's all jumbled up in my head and I'm having trouble making sense of it all.
     
  6. TwinFox

    TwinFox

    Joined:
    Jan 9, 2009
    Posts:
    66
    You should zero out the force components, not the velocity.

    If you think about it, gravity is pulling the car only straight downwards - acceleration is caused by the wheel force components acting perpendicular to it. If you zero these out, the wheel won't budge regardless of ground slope.
     
  7. ackyth

    ackyth

    Joined:
    Oct 29, 2009
    Posts:
    146
    Why not just zero the velocity once its under a set number?

    Should stop the slight movement creep and just set it up with a bool to toggle full stop on and off so it doesnt bother accelerating.

    Like so,

    if speed < #number car is not accelerating then set velocity to 0,0,0
     
  8. TwinFox

    TwinFox

    Joined:
    Jan 9, 2009
    Posts:
    66
    Forcing velocity to zero won't work, there will still be creeping. You can verify this by making a box with a rigidbody that is affected by gravity, and attaching script with
    Code (csharp):
    1. function Update() {
    2.     rigidbody.velocity = Vector3.zero;
    3. }
    The cube will still fall, although slower than before. Zeroing the lateral force components is what I'm currently using, and it is working well.
     
    noio likes this.
  9. Moreillon

    Moreillon

    Joined:
    Jul 13, 2014
    Posts:
    1
    When you consider that velocity is actually a measurement of distance over time. This means that as soon an an object has a velocity, it must have moved already.

    So zeroing an objects velocity would never keep an object perfectly still.
     
  10. SamFernGamer4k

    SamFernGamer4k

    Joined:
    May 20, 2018
    Posts:
    2
    I used to commit this same mistake. You should NEVER use physics related things in the Update loop, as it is frame rate dependant. You should use the FixedUpdate for this, as this ensures the physics simulation will execute right after all the FixedUpdate methods on all MonoBehaviour scripts are executed. The rigidbody was falling slowly because the physics loop and update loop are not meant to be synchronized.