I have some code I run when I fell a tree in my game. Basically it picks a random direction and then falls. However atm it linear and doesnt look very realistic. What Id want is for it to start slow, then speed up the more it's fallen.

I've been experimenting with animation curves but none of the material I can find works with my code:

public void FellTree()
    // pick a random point on the circle to match the up vector
    Vector2 pointOnCircle = UnityEngine.Random.insideUnitCircle * transform.localScale.y;

    // find the fall point, assuming the pivot of the object is at the bottom
    Vector3 fallPoint = transform.position +
        pointOnCircle.x * transform.right +
        pointOnCircle.y * transform.forward;

    // find the target up vector
    Vector3 updatedUpVector = Vector3.Normalize(fallPoint - transform.position);

    // Start the coroutine to tilt the up vector to the desired target
    StartCoroutine(UpdateUpVector(updatedUpVector, 1, 0.001f));

IEnumerator UpdateUpVector(Vector3 upVector, float speed, float threshold = 0.001f)
    // the target vector and up vector would get closer to each other until the threshold is hit
    while (Vector3.Distance(upVector, transform.up) > threshold)
        transform.up = Vector3.Lerp(transform.up, upVector, speed * Time.deltaTime);
        yield return new WaitForEndOfFrame();

Using animationCurve.Evaluate(float t) in the lerp should be what I need to do, but not working. How can I add an animation curve to my lerp?


1 Answer 1


You're using an exponential ease out lerp, which is not appropriate for combining with an animation curve. Use a linear lerp instead. Or a Slerp, since you're interpolating directions, to get more precise control over the rate of change using your animation curve.

public AnimationCurve curve;    

IEnumerator UpdateUpVector(Vector3 upVector, float duration)
    // Cache our initial orientation.
    Quaternion start = transform.rotation;

    // Form a new orientation, that tips our up vector over by 90 degrees.
    Vector3 axis = Vector3.Cross(transform.up, upVector);
    Quaternion end = Quaternion.AngleAxis(90f, axis) * start;

    // Gradually transition over our requested duration.
    float speed = 1f/duration;    
    for(float progress = 0f; progress < 1f; progress += Time.deltaTime * speed)
        // Transform our linear 0-1 progress into a non-linear curve.
        float nonLinear = curve.Evaluate(progress);

        // Blend between the two rotations, according to this curve value.
        transform.rotation = Quaternion.Slerp(start, end, nonLinear);

        // Wait until next frame.
        yield return null;

    // Fix-up any lingering fraction left over from the last frame of the loop.
    transform.rotation = end;
  • \$\begingroup\$ Had no idea, but this works perfectly, you are amazing \$\endgroup\$
    – Majs
    Commented May 26, 2020 at 17:58
  • \$\begingroup\$ One thing Im not managing to solve is the fact that the tree starts by rotating, then falls, which looks rly weird. I don't want the tree to rotate, I simply want it to fall in that direction. Can you see why that is? \$\endgroup\$
    – Majs
    Commented May 27, 2020 at 14:22
  • \$\begingroup\$ Turns out that it sets itself to y-rotation -90 before it begins, not sure why. I would like to place my trees at a random y-rotation so that is a bit of an issue. \$\endgroup\$
    – Majs
    Commented May 27, 2020 at 14:49
  • 1
    \$\begingroup\$ Because you told the transform which direction you wanted to be up - you didn't tell it what you wanted for any of the other axes, so it picked a default arbitrarily. To rotate something while controlling all axes, use Quaternions. I've demonstrated one such method in an edit. \$\endgroup\$
    – DMGregory
    Commented May 27, 2020 at 16:22
  • \$\begingroup\$ works perfectly, you are a wizard! \$\endgroup\$
    – Majs
    Commented May 27, 2020 at 16:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .