Moving to exact position with SmoothDamp?

Hi,
I am currently having the issue, that I am moving a Cube with Vector3.SmoothDamp,
but it always stops at like 2.99999 instead of the Target, 3.
How could I get it to move to exactly 3?

2.99999 is 3.0 with some tolerance. Do you really need more precision?

In general, don’t expect “exact” values when working with float numbers. Real numbers do not really exists inside a computer, because they are represented with a finite number of bits. And there are always floating-point arithmetic errors that creep in.

Smooth damp is for motion that never exactly reaches its target or doesn’t use an explict time to reach it, perfect for things like Camera following a target with some elasticity, since a camera doesn’t need to focus exactly on a point and in fact actually makes the motion feel more organic.

if you want something to have the smoothness of SmoothDamp but have a discrete duration and/or destination, try using smoothstep instead. Theres no Vector3 version of smoothStep by default, so you need to smoothstep a float then use it to lerp a vector.

public float duration = 5;

private IEnumerator SmoothStepToTarget(Vector3 targetPosition)
{
    Vector3 startPosition= transform.position;
    float lerp = 0;
    float smoothLerp = 0;

    while(lerp<1 && duration>0)
    {
        lerp = Mathf.MoveTowards(lerp,1,Time.deltaTime / duration);
        smoothLerp = Mathf.SmoothStep(0,1,lerp);
        transform.position = Vector3.Lerp(startPosition,targetPostion,smoothLerp);
        yield return null;
    }

    transform.position = targetPosition;
}
2 Likes

@JoshuaMcKenzie
I would use Lerp instead of MoveTowards to compute the linear lerp parameter. It just makes more sens (to me).

public float duration = 5.0f;

private IEnumerator SmoothStepToTarget(Vector3 targetPosition)
{
    Vector3 startPosition= transform.position;
    float lerp = 0.0f;
    float smoothLerp = 0.0f;
    float elapsedTime = 0.0f; // <--

    while(lerp < 1.0f && duration > 0.0f)
    {
        lerp = Mathf.Lerp(0.0f, 1.0f, elapsedTime / duration ); // <-- instead of Mathf.MoveTowards
        smoothLerp = Mathf.SmoothStep(0.0f, 1.0f, lerp);
        transform.position = Vector3.Lerp(startPosition, targetPostion, smoothLerp);
        elapsedTime += Time.deltaTime; // <--       
        yield return null;
    }
    transform.position = targetPosition;
}

To each his own. I prefer MoveTowards so that I don’t need to worry about overflow. plus I don’t need to keep a timer variable. It shouldn’t matter too much here, but in other Ease functions that I write which use LerpUnclamped it would cause the lerp to overshoot unintentionally