Search Unity

Question Calculate velocity needed to reach destination height... with drag / linear damping

Discussion in 'Physics for ECS' started by toomasio, Jan 21, 2021.

  1. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    Hello,

    I am trying to create a Step Up / Down system that works properly with physics.
    Does anybody have a velocity calculation for reaching a specific height?

    so far from research all I have is:
    Code (CSharp):
    1. var force = math.sqrt(2 * grav.Value * diff);
    but this calculation does not include drag. I am currently using linear damping on my controller.

    any ideas?

    Thanks,
     
  2. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Hi @toomasio , I'd just like to clarify your use case - do you want to move the body from pos A to pos B in 1 physics step or you'd like to provide a time interval to get there? Do you care about rotation and angular damping?
     
  3. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    @milos85miki Thanks for the reply. I have tried setting the translation value to move the body, but the physics calculations sometimes shoot the body up into the air - I am assuming because the capsule collider is clipping into the stairs collider. This was done using a lerp over certain amount of time (0.1f) but had awkward reactions with the dynamic physics on the controller.

    I figured I would have to add a physics force upward instead to get the player to basically "jump" up to the next step height. The problem is trying to make this modular. I have a system that gets the next step height, compares it to the players feet position, now I just need to calculate the velocity force needed to push the player up to the next step.

    example: https://i.imgur.com/bJnvuCj.mp4
     
    Last edited: Jan 21, 2021
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Got it, thanks! Have you tried using PhysicsWorldExtensions.CalculateVelocityToTarget()?

    There's an example in UnityPhysicsSamples\Assets\Demos\6. Use Cases\CharacterController. It works for most step heights, but not all, as it depends on the separating planes you get when casting capsule collider.
     
    toomasio likes this.
  5. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    Yeah unfortunately it doesn't look like this extension takes linear damping into account. Oh well. I will just multiply the force by some educated guess for now.
     
  6. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    No, it doesn't, but it's not crucial. It's not just about getting vertical velocity right, there's also horizontal velocity and character's position relative to the step. Again, I'd recommend reading the mentioned sample.

    If you want to consider damping, here's what you should know:
    1. Damping is applied at the end of the step, after body integration. So, we first do newPos = oldPos + velocity*dt and then reduce velocity by damping factor
    2. Velocity reduction by damping is calculated like this: velocity = velocity * (1 - damping*dt)
    3. If you want to calculate the influence of damping on velocity over multiple frames (which I don't think you need for character controller), binomial approximation might help.

    Hoping this helps!
     
    toomasio likes this.
  7. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
  8. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Sorry for not being clear, I mentioned that as an example of character controller implementation, not as CalculateVelocityToTarget usage. CharacterControllerJob accounts for all character collisions with the world and drives the character completely (including position integration in each step).
     
    toomasio likes this.
  9. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Last edited: Jan 27, 2021
    toomasio likes this.
  10. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    I derived some methods a long time ago, I had to make an adjustment for it to work with classic unity, not sure if these work in DOTS. If you need to redo these, you can use wolfram alpha to do the heavy lifting for you.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public static class Predict
    5. {
    6.     public static float Distance(float speed, float drag, float time)
    7.     {
    8.         var characteristicTime = 1 / drag;
    9.         return (float) (speed * characteristicTime * (1 - Math.Pow(Math.E, -time / characteristicTime)));
    10.     }
    11.  
    12.     public static float Speed(float speed, float distance, float drag)
    13.     {
    14.         var characteristicTime = 1 / drag;
    15.         var time = Time(speed, distance, drag);
    16.         return (float) (speed * Math.Pow(Math.E, -time / characteristicTime));
    17.     }
    18.  
    19.     public static float Time(float speed, float distance, float drag)
    20.     {
    21.         var characteristicTime = 1 / drag;
    22.         return (float) (characteristicTime * Math.Log(characteristicTime * speed / (characteristicTime * speed - distance)));
    23.     }
    24.  
    25.     public static Vector3 Position(Vector3 velocity, float drag, float time)
    26.     {
    27.         var characteristicTime = 1 / drag;
    28.         return velocity * characteristicTime * (float) (1 - Math.Pow(Math.E, -time / characteristicTime));
    29.     }
    30.  
    31.     public static Vector3 Position(Vector3 velocity, float drag, float time, Vector3 force, float mass)
    32.     {
    33.         var terminalVelocity = force / drag / mass;
    34.         var characteristicTime = 1 / drag;
    35.         var compound = (float)Math.Pow(Math.E, -time / characteristicTime);
    36.         return terminalVelocity * time + velocity * characteristicTime * (1 - compound) + terminalVelocity * characteristicTime * (compound - 1);
    37.     }
    38.  
    39.     public static Vector3 Force(Vector3 velocity, float drag, float time, Vector3 target, float mass)
    40.     {
    41.         var compound = (float)Math.Pow(Math.E, drag*time);
    42.         return drag * mass * (drag * target * compound - velocity * compound + velocity) / (compound * (drag * time - 1) + 1);
    43.     }
    44.  
    45.     public static Vector3 Velocity(Vector3 force, float drag, float time, Vector3 target, float mass)
    46.     {
    47.         var compound = (float)Math.Pow(Math.E, drag*time);
    48.         return (drag * drag * mass * target * compound + force * (compound * (1 - drag * time) - 1)) / (drag * mass * (compound - 1));
    49.     }
    50. }
    Note that certain queries can not be calculated directly, but need to be iterated on to get an acceptable result
     
    Last edited: Jan 26, 2021
    steveeHavok, petarmHavok and toomasio like this.
  11. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    @Bas-Smit tons of useful functions here. Thanks!
     
  12. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    a burst port of the above and much more is now available here :)

    https://github.com/bassmit/util

    Disclaimer, I only tested Velocity (see Predict Test scene) which works as expected
     
    petarmHavok, toomasio and steveeHavok like this.