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

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:

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,

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?

@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: Imgur: The magic of the Internet

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.

1 Like

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.

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!

1 Like

Where in the sample am I supposed to look at?
https://github.com/Unity-Technologies/EntityComponentSystemSamples/tree/master/UnityPhysicsSamples/Assets/Demos/6.%20Use%20Cases/CharacterController/Scripts
I am not seeing CalculateVelocityToTarget anywhere in the controller scripts.

I still ended up using this function, and will use your math to calculate the damping. Thanks for your help!

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).

1 Like

The math is not easy, but is given here Motion with linear drag

1 Like

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.

using System;
using UnityEngine;

public static class Predict
{
    public static float Distance(float speed, float drag, float time)
    {
        var characteristicTime = 1 / drag;
        return (float) (speed * characteristicTime * (1 - Math.Pow(Math.E, -time / characteristicTime)));
    }

    public static float Speed(float speed, float distance, float drag)
    {
        var characteristicTime = 1 / drag;
        var time = Time(speed, distance, drag);
        return (float) (speed * Math.Pow(Math.E, -time / characteristicTime));
    }

    public static float Time(float speed, float distance, float drag)
    {
        var characteristicTime = 1 / drag;
        return (float) (characteristicTime * Math.Log(characteristicTime * speed / (characteristicTime * speed - distance)));
    }

    public static Vector3 Position(Vector3 velocity, float drag, float time)
    {
        var characteristicTime = 1 / drag;
        return velocity * characteristicTime * (float) (1 - Math.Pow(Math.E, -time / characteristicTime));
    }

    public static Vector3 Position(Vector3 velocity, float drag, float time, Vector3 force, float mass)
    {
        var terminalVelocity = force / drag / mass;
        var characteristicTime = 1 / drag;
        var compound = (float)Math.Pow(Math.E, -time / characteristicTime);
        return terminalVelocity * time + velocity * characteristicTime * (1 - compound) + terminalVelocity * characteristicTime * (compound - 1);
    }

    public static Vector3 Force(Vector3 velocity, float drag, float time, Vector3 target, float mass)
    {
        var compound = (float)Math.Pow(Math.E, drag*time);
        return drag * mass * (drag * target * compound - velocity * compound + velocity) / (compound * (drag * time - 1) + 1);
    }

    public static Vector3 Velocity(Vector3 force, float drag, float time, Vector3 target, float mass)
    {
        var compound = (float)Math.Pow(Math.E, drag*time);
        return (drag * drag * mass * target * compound + force * (compound * (1 - drag * time) - 1)) / (drag * mass * (compound - 1));
    }
}

Note that certain queries can not be calculated directly, but need to be iterated on to get an acceptable result

3 Likes

@Bas-Smit tons of useful functions here. Thanks!

a burst port of the above and much more is now available here :slight_smile:

Disclaimer, I only tested Velocity (see Predict Test scene) which works as expected

3 Likes